.NET gerado automaticamente cliente de serviço web: Como evitar solicitando esquemas de w3.org?

StackOverflow https://stackoverflow.com/questions/217841

Pergunta

Eu tenho um cliente de serviço web .NET que foi gerada automaticamente a partir de um arquivo WSDL usando a ferramenta wsdl.exe.

Quando eu instanciar a classe gerado, ele começa a pedir um monte de documentos de w3.org e outros. Sendo a primeira http://www.w3.org/2001/XMLSchema.dtd

Além de não querer causar tráfego desnecessário w3.org, eu preciso ser capaz de executar o aplicativo sem uma conexão com a Internet (o serviço web é um "Intra-web-service").

Alguém sabe a solução?

Se ele ajuda, aqui é o stacktrace eu recebo quando eu não tenho Internet:

"An error has occurred while opening external DTD 'http://www.w3.org/2001/XMLSchema.dtd': The remote name could not be resolved: 'www.w3.org'"

   at System.Net.HttpWebRequest.GetResponse()
   at System.Xml.XmlDownloadManager.GetNonFileStream(Uri uri, ICredentials credentials)
   at System.Xml.XmlDownloadManager.GetStream(Uri uri, ICredentials credentials)
   at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn)
   at System.Xml.XmlTextReaderImpl.OpenStream(Uri uri)
   at System.Xml.XmlTextReaderImpl.DtdParserProxy_PushExternalSubset(String systemId, String publicId)

   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.DtdParserProxy_PushExternalSubset(String systemId, String publicId)
   at System.Xml.XmlTextReaderImpl.DtdParserProxy.System.Xml.IDtdParserAdapter.PushExternalSubset(String systemId, String publicId)
   at System.Xml.DtdParser.ParseExternalSubset()
   at System.Xml.DtdParser.ParseInDocumentDtd(Boolean saveInternalSubset)
   at System.Xml.DtdParser.Parse(Boolean saveInternalSubset)
   at System.Xml.XmlTextReaderImpl.DtdParserProxy.Parse(Boolean saveInternalSubset)
   at System.Xml.XmlTextReaderImpl.ParseDoctypeDecl()
   at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
   at System.Xml.XmlTextReaderImpl.Read()
   at System.Xml.Schema.Parser.StartParsing(XmlReader reader, String targetNamespace)
   at System.Xml.Schema.Parser.Parse(XmlReader reader, String targetNamespace)
   at System.Xml.Schema.XmlSchemaSet.ParseSchema(String targetNamespace, XmlReader reader)
   at System.Xml.Schema.XmlSchemaSet.Add(String targetNamespace, XmlReader schemaDocument)
   at [...]WebServiceClientType..cctor() in [...]
Foi útil?

Solução 2

Eu precisava do XmlResolver, então o Tamberg solução não funcionou muito bem. Eu resolvi isso através da implementação de minha própria XmlResolver que ler os esquemas necessários de recursos incorporados em vez de baixá-los.

O problema não tem nada a ver com o código gerado automaticamente, pelo caminho.

A web-service-cliente tinha um outro arquivo de implementação que continha algo como isto:

public partial class [...]WebServiceClientType
  {
    private static readonly XmlSchemaSet _schema;

    static KeyImportFileType()
    {
      _schema = new XmlSchemaSet();
      _schema.Add(null, XmlResourceResolver.GetXmlReader("http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"));
      _schema.Add(null, XmlResourceResolver.GetXmlReader("http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/xenc-schema.xsd"));
      _schema.Compile();
    }

e foi essa classe-construtor que falhou.

Outras dicas

Se você tem acesso ao XmlReader (ou XmlTextReader), você pode fazer o seguinte:

XmlReader r = ...
r.XmlResolver = null; // prevent xsd or dtd parsing

Saudações, Tamberg

Aqui está a minha solução. Espero que ele salva alguém de ter de depuração através do .NET framework que eu tinha que trabalhar os fundamentos da XmlUrlResolver. Ele quer de carga de um recurso local (arquivo de texto resx), cache, ou comportamento padrão uso XmlUrlResolver:

using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Net;
using System.Net.Cache;
using System.IO;
using System.Resources;

namespace AxureExport {

    //
    // redirect URL resolution to local resource (or cache)
    public class XmlCustomResolver : XmlUrlResolver {

        ICredentials _credentials;
        ResourceManager _resourceManager;

        public enum ResolverType { useDefault, useCache, useResource };
        ResolverType _resolverType;

        public XmlCustomResolver(ResolverType rt, ResourceManager rm = null) {
            _resourceManager = rm != null ? rm : AxureExport.Properties.Resources.ResourceManager;
            _resolverType = rt;
        }

        public override ICredentials Credentials {
            set {
                _credentials = value;
                base.Credentials = value;
            }
        }

        public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn) {
            object response = null;

            if (absoluteUri == null)
                throw new ArgumentNullException(@"absoluteUri");

            switch (_resolverType) {
                default:
                case ResolverType.useDefault:                   // use the default behavior of the XmlUrlResolver
                    response = defaultResponse(absoluteUri, role, ofObjectToReturn);
                    break;

                case ResolverType.useCache:                     // resolve resources thru cache
                    if (!isExternalRequest(absoluteUri, ofObjectToReturn)) {
                        response = defaultResponse(absoluteUri, role, ofObjectToReturn);
                        break;
                    }

                    WebRequest webReq = WebRequest.Create(absoluteUri);
                    webReq.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.Default);
                    if (_credentials != null)
                        webReq.Credentials = _credentials;

                    WebResponse wr = webReq.GetResponse();
                    response = wr.GetResponseStream();
                    break;

                case ResolverType.useResource:                  // get resource from internal resource
                    if (!isExternalRequest(absoluteUri, ofObjectToReturn)) {
                        response = defaultResponse(absoluteUri, role, ofObjectToReturn);    // not an external request
                        break;
                    }

                    string resourceName = uriToResourceKey(absoluteUri);
                    object resource = _resourceManager.GetObject(resourceName);
                    if (resource == null)
                        throw new ArgumentException(@"Resource not found.  Uri=" + absoluteUri + @" Local resourceName=" + resourceName);

                    if (resource.GetType() != typeof(System.String))
                        throw new ArgumentException(resourceName + @" is an unexpected resource type.  (Are you setting resource FileType=Text?)");

                    response = ObjectToUTF8Stream(resource);
                    break;
            }

            return response;
        }

        //
        // convert object to stream
        private static object ObjectToUTF8Stream(object o) {
            MemoryStream stream = new MemoryStream();

            StreamWriter writer = new StreamWriter(stream, Encoding.UTF8);
            writer.Write(o);
            writer.Flush();
            stream.Position = 0;

            return stream;
        }

        //
        // default response is to call tbe base resolver
        private object defaultResponse(Uri absoluteUri, string role, Type ofObjectToReturn) {
            return base.GetEntity(absoluteUri, role, ofObjectToReturn);
        }

        //
        // determine whether this is an external request
        private static bool isExternalRequest(Uri absoluteUri, Type ofObjectToReturn) {
            return absoluteUri.Scheme == @"http" && (ofObjectToReturn == null || ofObjectToReturn == typeof(Stream));
        }

        //
        // translate uri to format compatible with reource manager key naming rules
        // see: System.Resources.Tools.StronglyTypedResourceBuilder.VerifyResourceName Method
        //   from http://msdn.microsoft.com/en-us/library/ms145952.aspx:
        private static string uriToResourceKey(Uri absoluteUri) {
            const string repl = @"[ \xA0\.\,\;\|\~\@\#\%\^\&\*\+\-\/\\\<\>\?\[\]\(\)\{\}\" + "\"" + @"\'\:\!]+";
            return Regex.Replace(Path.GetFileNameWithoutExtension(absoluteUri.LocalPath), repl, @"_");
        }
    }
}

Graças Tamberg, você me salvou uma grande quantidade de tempo com a sua resposta sucinta e correta. Eu não sabia que o padrão resolvedor iria para a web. Verificando MSDN é estados -

XmlResolver é o resolvedor padrão para todas as classes no namespace System.Xml. Você também pode criar seu próprio resolvedor ...

Eu tenho implementado sua resposta, definindo o resolvedor para NULL que resolve o problema e reduz a sobrecarga de rede.

XmlReader r = ...r.XmlResolver = null; // prevent xsd or dtd parsing

Obrigado novamente, Andy

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top