.NET自动生成的Web服务客户端:如何避免从w3.org请求架构?

我有一个.NET Web服务客户端,它使用wsdl.exe工具从wsdl文件自动生成。

当我第一次实例化生成的类时,它开始从w3.org和其他人那里请求一堆文档。 第一个是http://www.w3.org/2001/XMLSchema.dtd

除了不想给w3.org带来不必要的流量之外,我还需要能够在没有连接到Internet的情况下运行应用程序(Web服务是“Intra-web-service”)。

有人知道解决方案吗?

如果它有帮助,这是我没有互联网时得到的堆栈跟踪:

"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 [...] 

如果您有权访问XmlReader(或XmlTextReader),则可以执行以下操作:

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

此致,tamberg

我需要XmlResolver,所以tamberg的解决方案并不是很有效。 我通过实现自己的XmlResolver来解决它,它从嵌入式资源中读取必要的模式而不是下载它们。

顺便提一下,问题与自动生成的代码没有任何关系。

web-service-client有另一个实现文件包含这样的内容:

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

这个类构造函数失败了。

这是我的解决方案。 我希望它可以节省一些人不必通过.NET框架进行调试,就像我必须找出XmlUrlResolver的基础一样。 它将从本地资源(resx文本文件)加载,缓存或使用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, @"_"); } } } 

谢谢Tamberg,你用简洁而正确的答案为我节省了大量时间。 我没有意识到默认的解析器会进入网络。 检查MSDN是状态 –

XmlResolver是System.Xml命名空间中所有类的默认解析程序。 你也可以创建自己的解析器……

我已经实现了你的答案,将解析器设置为NULL,这解决了问题并减少了网络开销。

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

再次感谢,安迪