Click to Rate and Give Feedback
MSDN
MSDN Library
.NET Development
Previous Versions
.NET Framework 1.1
.NET Framework
 Creating a Custom Resolver
.NET Framework Developer's Guide
Creating a Custom Resolver

This topic shows an example of extending the XmlUrlResolver class to cache a stream to the hard disk. All calls to GetEntity cause the stream returned by the GetEntity method to be saved to the c:\temp directory. This is useful when the resources are being resolved over a network. Caching overrides the GetEntity method.

Because the custom XmlResolver is using the XmlUrlResolver and not the XmlSecureResolver shipped in .NET Framework version 1.1, no cross-domain checking is performed when redirection occurs. This means that any embedded URI that causes redirection caused by includes, imports, referencing external entities, and so on, will read the data without checking any kind of security on the data or site. This is because no credentials are passed when the redirection occurs, and, your application can be compromised by obtaining data from an insecure or anonymous site.

In the code sample below, a static Hashtable, myHash, stores information about the URIs that have been resolved. When a URI is resolved for the first time, the stream is stored in a file and a stream representing the file is returned. An entry in the Hashtable is also made using the URI as the key, with the filename as its value. On subsequent attempts to resolve the URI, the Hashtable is checked and the stream that is currently cached on the hard drive is used. If multiple instances of this class are run on different processes, then additional code is required to ensure that filenames are unique. The following code example assumes that the folder c:\resolver_cache exists. The following example is the full code for the class.

[Visual Basic]
Class CustomResolver
Inherits XmlUrlResolver
Public Shared myHash As New Hashtable()

Public Sub New()
End Sub 'New
      
Public Overrides Function GetEntity(absoluteUri As Uri, role As String, ofObjectToReturn As Type) As Object
If myHash.ContainsKey(absoluteUri) Then
    Console.Out.WriteLine(("Reading resource" + absoluteUri.ToString() + " from cached stream"))
    'Returns the cached stream.
    Return New FileStream(CType(myHash(absoluteUri), [String]), FileMode.Open, FileAccess.Read, FileShare.Read)
Else
    ' The filename that the cached stream is stored to.
    Dim filename As [String] = "c:\resolver_cache\resolve" + CStr(myHash.Count) + ".txt"
    Console.Out.WriteLine(filename)
    ' Create a new stream representing the file to be written to,
    ' and write the stream cache from the external
    ' location to the file.
    Dim fStream As New FileStream(filename, FileMode.Create)
    Dim sRead As New StreamReader(CType(MyBase.GetEntity(absoluteUri, role, ofObjectToReturn), Stream))
    Dim sWrite As New StreamWriter(fStream)
    sWrite.Write(sRead.ReadToEnd())
    ' Add the information about the cached Uri to the hashtable.
    myHash.Add(absoluteUri, filename)
    ' Close any open streams.
    sWrite.Close()
    sRead.Close()
    Return New FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)
    End If
  End Function 'GetEntity
End Class 'CustomResolver
[C#]
class CustomResolver : XmlUrlResolver
{
public static Hashtable myHash=new Hashtable();
public CustomResolver()
{
}
override public object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
{
if(myHash.ContainsKey(absoluteUri))
    {
    Console.Out.WriteLine("Reading resource"+absoluteUri.ToString()+" from cached stream");
    // Returns the cached stream.
    return new FileStream((String)myHash[absoluteUri],FileMode.Open,FileAccess.Read,FileShare.Read);
    }
else
    {
    // The filename that the cached stream will be stored to.
    String filename = "c:\\resolver_cache\\resolve"+myHash.Count+ ".txt";
    Console.Out.WriteLine(filename);
    // Create a new stream representing the file to be written to,
    // and write the stream cache the stream
    // from the external location to the file.
    FileStream fStream = new FileStream(filename, FileMode.Create);
    StreamReader sRead = new StreamReader((Stream)base.GetEntity(absoluteUri, role, ofObjectToReturn));
    StreamWriter sWrite = new StreamWriter(fStream);
    sWrite.Write(sRead.ReadToEnd());
    // Add the information about the cached Uri to the hashtable.
    myHash.Add(absoluteUri,filename);
    // Close any open streams.
    sWrite.Close();
    sRead.Close();
    return new FileStream(filename, FileMode.Open,FileAccess.Read,FileShare.Read); 
    }
  }
}

If you want to create a custom resolver to resolve resources using protocols other than http://, https:// or file://, you need to override the GetEntity method to handle the connection.

If you want to use a different URI as the baseUri, you need to override the ResolveUri method to use a fixed baseURI, regardless of the parameters passed into the method. For example, if you wanted to set all URIs to be resolved using a given baseURI, the following code example shows how you could create a new property BaseURI.

[Visual Basic]
Dim baseUri As Uri

Public Property BaseURI() As Uri
   Get
      Return baseUri
   End Get
   Set
      baseUri = value
   End Set
End Property
[C#]
Uri _baseUri;
public Uri BaseURI
{
    get{ return _baseUri;}
    set{ _baseUri = value;}
   }

Using this property you can override the ResolveUri property to be:

[Visual Basic]
Public Overrides Function ResolveUri(baseUri As Uri, relativeUri As [String]) As Uri
   Return MyBase.ResolveUri(BaseURI, relativeUri)
End Function 'ResolveUri
[C#]
public override Uri ResolveUri(Uri baseUri, String relativeUri)
    {
        return base.ResolveUri(BaseURI,relativeUri);
    }

See Also

Resolve External XML Resources Named by a URI | Resolving Resources using theXmlResolver | Supplying Authentication Credentials to XmlResolver when Reading from a File

© 2009 Microsoft Corporation. All rights reserved. Terms of Use | Trademarks | Privacy Statement
Page view tracker