我有一个.NET Web服务客户端,它是使用wsdl.exe工具从wsdl文件自动生成的。
当我第一次实例化生成的类时,它开始从w3.org和其他人那里请求一堆文档。第一个是http://www.w3.org/2001/XMLSchema.dtd
除了不想给w3.org带来不必要的流量外,我还需要能够在没有连接到互联网的情况下运行应用程序(网络服务是“内部网络服务”)。
任何人都知道解决方案吗?
如果有帮助,这是我没有互联网时的堆栈跟踪:
"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 [...]
答案 0 :(得分:4)
如果您有权访问XmlReader(或XmlTextReader),则可以执行以下操作:
XmlReader r = ...
r.XmlResolver = null; // prevent xsd or dtd parsing
此致 tamberg
答案 1 :(得分:4)
我需要XmlResolver,所以tamberg's solution没有用。我通过实现自己的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();
}
这个类构造函数失败了。
答案 2 :(得分:1)
这是我的解决方案。我希望它可以节省一些人不必通过.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, @"_");
}
}
}
答案 3 :(得分:0)
感谢Tamberg,你用简洁而正确的答案为我节省了大量时间。我没有意识到默认的解析器会进入网络。检查MSDN是状态 -
XmlResolver是System.Xml命名空间中所有类的默认解析程序。您也可以创建自己的解析器......
我已经实现了你的答案,将解析器设置为NULL可以解决问题并减少网络开销。
XmlReader r = ...r.XmlResolver = null; // prevent xsd or dtd parsing
再次感谢, 安迪