2008-10-20 15 views
2

J'ai un client de service Web .NET qui a été généré automatiquement à partir d'un fichier wsdl à l'aide de l'outil wsdl.exe. Lorsque j'instancie la classe générée pour la première fois, elle commence à demander un tas de documents à partir de w3.org et d'autres. Le premier étant http://www.w3.org/2001/XMLSchema.dtdClient de service Web autogénéré .NET: Comment éviter de demander des schémas à partir de w3.org?

En plus de ne pas vouloir causer de trafic inutile à w3.org, je dois pouvoir exécuter l'application sans connexion à Internet (le web-service est un "Intra-web-service").

Quelqu'un connait la solution?

Si elle aide, voici le stacktrace que je reçois quand je n'ai pas 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 [...] 

Répondre

4

je besoin XmlResolver, donc tamberg's solution n'a pas fonctionné tout à fait. Je l'ai résolu en implémentant mon propre XmlResolver qui lit les schémas nécessaires à partir de ressources intégrées au lieu de les télécharger.

Le problème n'avait rien à voir avec le code autogénéré, d'ailleurs.

Le service-client Web avait un autre fichier de mise en œuvre qui contenait quelque chose comme ceci:

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(); 
    } 

et il était cette classe constructeur qui a échoué.

4

si vous avez accès à XmlReader (ou XmlTextReader) vous pouvez effectuer les opérations suivantes:

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

Cordialement, Tamberg

0

Merci Tamberg, vous m'avez fait gagner beaucoup de temps avec votre réponse succincte et correcte. Je n'ai pas réalisé que le résolveur par défaut irait sur le web. Vérification de MSDN est des états -

XmlResolver est le résolveur par défaut pour toutes les classes dans l'espace de noms System.Xml. Vous pouvez créer votre propre résolveur ...

J'ai mis votre réponse, le réglage du résolveur à NULL qui résout le problème et réduit la surcharge du réseau.

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

Merci encore, Andy

1

Voici ma solution. J'espère que cela évitera à quelqu'un d'avoir à déboguer à travers le framework .NET comme je l'ai dû pour travailler sur les fondements de XmlUrlResolver. Il chargera à partir d'une ressource locale (fichier texte resx), du cache ou utilisera le comportement par défaut de 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, @"_"); 
     } 
    } 
}