如何通过代理使用.dtd验证xml而不使用system.net.defaultproxy

时间:2010-05-04 14:52:06

标签: c# xml proxy dtd

其他人已经问了一个类似的问题:Validate an Xml file against a DTD with a proxy. C# 2.0

这是我的问题:我们有一个网站应用程序,需要使用内部和外部资源。

  1. 我们有一堆内部的 网页服务。对CAN NOT的请求 通过代理。如果我们尝试,我们会收到404错误,因为代理DNS不知道我们的内部Web服务域。
  2. 我们生成一个 几个必须有效的xml文件。 我想使用提供的dtd 用于验证xml的文档。该 dtd网址在我们的网络之外 必须通过代理。
  3. 有没有办法通过代理验证通过代理而不使用system.net.defaultproxy?如果我们使用defaultproxy,则内部Web服务被破坏,但dtd验证有效。#

    以下是我正在做的用于验证xml的内容:

    public static XDocument ValidateXmlUsingDtd(string xml)
    {
        var xrSettings = new XmlReaderSettings {
            ValidationType = ValidationType.DTD,
            ProhibitDtd = false
        };
    
        var sr = new StringReader(xml.Trim());
    
        XmlReader xRead = XmlReader.Create(sr, xrSettings);
        return XDocument.Load(xRead);
    }
    

    理想情况下,可以通过某种方式为XmlReader分配代理,就像您可以为HttpWebRequest对象分配代理一样。或者也许有一种方法以编程方式打开或关闭defaultproxy?所以我可以打开它来调用Load the Xdocument,然后再把它关掉?

    仅供参考 - 我对如何解决此问题持开放态度 - 请注意,代理位于另一个域中,他们不希望为我们的内部Web服务地址设置dns查找到我们的dns服务器

    干杯, 兰斯

1 个答案:

答案 0 :(得分:1)

是的,你可以解决这个问题。

一种选择是创建自己的解析器来处理DTD分辨率。它可以使用它喜欢的任何机制,包括使用非默认代理进行出站通信。

 var xmlReaderSettings = new XmlReaderSettings
     {
         ProhibitDtd = false,
         ValidationType = ValidationType.DTD, 
         XmlResolver = new MyCustomDtdResolver()
     };

在MyCustomDtdResolver的代码中,您可以指定所需的代理设置。它可能会有所不同,具体取决于DTD。

您没有指定,但是如果您要解决的DTD是固定且不变的,那么Silverlight和.NET 4.0都有一个内置的解析器,它不会触及网络(没有代理,也没有任何http通信)。它被称为XmlPreloadedResolver。开箱即用,它知道如何解决RSS091和XHTML1.0。如果您有其他DTD,包括您自己的自定义DTD,并且它们是固定的或不变的,您可以将它们加载到此解析程序中并在运行时使用它,并完全避免HTTP通信和代理复杂化。

More on that.

如果您不使用.NET 4.0,那么您可以自己构建一个“无网络”解析器。为了避免W3C traffic limit,我构建了a custom resolver myself, for XHTML,也许你可以重复使用它。

另见a related link


为了说明,这里是自定义Uri解析器中ResolveUri的代码。

/// <summary>
///   Resolves URIs.
/// </summary>
/// <remarks>
///   <para>
///     The only Uri's supported are those for W3C XHTML 1.0.
///   </para>
/// </remarks>
public override Uri ResolveUri(Uri baseUri, string relativeUri)
{
    if (baseUri == null)
    {
        if (relativeUri.StartsWith("http://"))
        {
            Trace("  returning {0}", relativeUri);
            return new Uri(relativeUri);
        }
        // throw if Uri scheme is unknown/unhandled
        throw new ArgumentException();
    }

    if (relativeUri == null)
        return baseUri;

    // both are non-null
    var uri = baseUri.AbsoluteUri;
    foreach (var key in knownDtds.Keys)
    {
        // look up the URI in the table of known URIs
        var dtdUriRoot = knownDtds[key];
        if (uri.StartsWith(dtdUriRoot))
        {
            string newUri = uri.Substring(0,dtdUriRoot.Length) + relativeUri;
            return new Uri(newUri);
        }
    }

    // must throw if Uri is unknown/unhandled
    throw new ArgumentException();
}

这是GetEntity的代码

/// <summary>
///   Gets the entity associated to the given Uri, role, and
///   Type.
/// </summary>
/// <remarks>
///   <para>
///     The only Type that is supported is the System.IO.Stream.
///   </para>
///   <para>
///     The only Uri's supported are those for W3C XHTML 1.0.
///   </para>
/// </remarks>
public override object GetEntity(Uri absoluteUri, string role, Type t)
{
    // only handle streams
    if (t != typeof(System.IO.Stream))
        throw new ArgumentException();

    if (absoluteUri == null)
        throw new ArgumentException();

    var uri = absoluteUri.AbsoluteUri;
    foreach (var key in knownDtds.Keys)
    {
        if (uri.StartsWith(knownDtds[key]))
        {
            // Return the stream containing the requested DTD. 
            // This can be a FileStream, HttpResponseStream, MemoryStream, 
            // or whatever other stream you like.  I used a Resource stream
            // myself.  If you retrieve the DTDs via HTTP, you could use your
            // own IWebProxy here.  
            var resourceName = GetResourceName(key, uri.Substring(knownDtds[key].Length));
            return GetStreamForNamedResource(resourceName);
        }
    }

    throw new ArgumentException();
}

我的自定义解析程序is available的完整工作代码。

如果您的解析程序执行网络通信,那么对于常规解决方案,您可能希望覆盖Credentials属性。

public override System.Net.ICredentials Credentials
{
    set { ... }
}

此外,您可能希望公开代理属性。或不。如上所述,您可能希望从DTD URI自动确定要使用的代理。