How to validate xml using .dtd via proxy and NOT using system.net.defaultproxy

Someone else asked a somewhat similar question: Validate Xml file versus DTD using proxy. C # 2.0

Here's my problem: we have a web application that needs to use both internal and external resources.

  • We have a bunch of internal WebServices. Requests to CAN NOT go through the proxy. If we try, we'll get 404 errors as the DNS proxy doesn't know about our internal webservice domains.
  • We generate several xml files that must be valid. I would like to use the provided dtd docs to validate the xml. Dtd urls are outside of our network. MUST go through the proxy.

Is there a way to check through dtd via proxy without using system.net.defaultproxy? If we use defaultproxy the internal webservices are ruined but the dtd validation works. #

Here's what I am doing to validate the xml right now:

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

      

Ideally, you could assign a proxy to an XmlReader in the same way you can assign a proxy to an HttpWebRequest object. Or maybe there is a way to programmatically enable or disable the defaultproxy function? So that I can just enable it to call Load Xdocument and then disable it again?

FYI. I am open to thinking about how to handle this. Please note that the proxy is on a different domain and they don't want to set up a dns lookup to our DNS server for our internal web service addresses.

Cheers, Spear

+2


a source to share


1 answer


Yes, you can fix that.

One option is to create your own resolver that handles DTD resolution. He can use any mechanism he likes, including using a non-default proxy for outgoing messages.

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

      

In the code for MyCustomDtdResolver, you must specify the desired proxy setting. It may vary depending on the DTD.

You didn't specify, but if the DTDs you allow are fixed and immutable, then Silverlight and .NET 4.0 have a built-in resolver that doesn't hit the web (no proxy, no http compromises). It's called XmlPreloadedResolver . Out of the box, it knows how to resolve RSS091 and XHTML1.0. If you have other DTDs, including your own DTDs, and they are fixed or immutable, you can load them into this transformer and use it at runtime, and avoid HTTP commands and proxy complications entirely.

More on this.

If you are not using .NET 4.0, you can create a "no network" resolver yourself. To avoid W3C traffic limitation , I built my own custom resolver, for XHTML , maybe you can reuse it.

See also the linked link .




For illustration purposes, here is the ResolveUri code at a custom Uri resolution.

/// <summary>
///   Resolves URIs.
/// </summary>
/// <remarks>
///   <para>
///     The only Uri 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();
}

      

here's the code for 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 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();
}

      

Full working code available for my custom converter.

If your transducer does network communications, then for a general solution you can override the Credentials property.

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

      

Alternatively, you can open the Proxy property. Or not. As I said above, you can automatically detect the proxy to use with the DTD URI.

+1


a source







All Articles