2010-05-04 40 views
2

有人已問了一個有點類似的問題來驗證XML:Validate an Xml file against a DTD with a proxy. C# 2.0如何通過代理使用.dtd和不使用system.net.defaultproxy

這裏是我的問題:我們需要使用一個網站應用內部和外部資源。

  1. 我們有一堆內部 webservices。請求CAN NOT 通過代理。如果我們嘗試去做,我們會得到404錯誤,因爲代理DNS不知道我們的內部Web服務域。
  2. 我們生成一個 幾個必須有效的xml文件。 我想使用提供的dtd 文檔來驗證xml。 dtd網址在我們的網絡之外, 必須通過代理。

有沒有辦法通過DTD通過代理來驗證不使用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?所以我可以打開它來調用加載Xdocument,然後再關閉它?

僅供參考 - 關於如何解決這個問題的想法是開放的 - 請注意,代理位於另一個域中,並且他們不想爲我們的內部Web服務設置dns查找到我們的dns服務器地址。

乾杯, 蘭斯

回答

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


例如,以下是ResolveUri在自定義Uri解析器中的代碼。

/// <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

如果您的解析程序執行網絡通信,那麼對於一般的解決方案,您可能需要重寫憑證屬性。

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

另外,您可能希望公開Proxy屬性。或不。正如我上面所說的,您可能想要從DTD URI自動確定要使用的代理。

+0

感謝Cheeso的回覆。 你能爲MyCustomDtdResolver顯示一些代碼嗎?就像你在http://stackoverflow.com/questions/2558021/an-error-has-occurred-opening-extern-dtd-w3-org-xhtml1-transitional-dtd-503/2559056#2559056中說的那樣,文檔非常* *很少。我特別感興趣的是ResolveUri和GetEntity方法應該包含什麼以啓用通過代理獲取dtd。 – Lanceomagnifico 2010-05-05 08:28:51

+0

哦,我沒有忘記提到這個解決方案需要在.NET 3.5 – Lanceomagnifico 2010-05-05 08:31:53

+1

中工作好,我會用一些代碼更新答案。 – Cheeso 2010-05-05 13:05:21