XmlResourceResolver — A specific System.Xml.XmlResolver used to find resources stored as manifest resource streams in an assembly

Problem

I wanted to:

The new System.Xml.XmlResolver class in .NET 1.1 looked promising!

I knew about the Assembly.GetManifestResourceStream call to load the embedded XSLT files as a Stream into my program. I also found that by including the culture identifier in the file name (between the name & the extension) that VS.NET will create the respective satellite assemblies for you, with the XSLT file embedded. Unfortunately looking at ResourceManager was not giving me what I needed...

What I was missing was how to find the satellite assemblies.

A quick search on Google lead me to Shawn A. Van Ness’ article I Hate ResX Files giving me to the piece I was missing Assembly.GetSatelliteAssembly.

I must have been looking too hard at ResourceManager to have noticed Assembly.GetSatelliteAssembly! :-)

Solution

The XmlResourceResolver class is my solution; I hope you find it useful. Like Shawn’s ResourceLoader class, it can be used for any type of embedded resource, not just XSLT files!

Discussion

MemberDescription
m_assemblyDefines the primary Assembly where the embedded resources are found.
m_typeDefines the Type that is used to indentify the namespace where the embedded resources are.

NOTE: Only the namespace of this Type is used.

New(type)Initializes the m_assembly & m_type fields.
CredentialsNot supported.
ResolveUri(baseUri, relativeUri)Overridden to set the baseUri to the Assembly.Location if the baseUri is not given.
GetEntity(absoluteUri, role, ofObjectToReturn)Returns a Stream representing the resource from the first of the following places:
  • File in same location as assembly
  • Specific Culture Assembly (de-DE)
  • Specific Culture's Parent Assembly (de)
  • The primary assembly itself
If the resource is not found in any of the four places a FileNotFoundException is thrown.
GetManifestResourceStream(culture, name)Helper function used by GetEntity to find the resource in a satellite assembly.
GetManifestResourceStream(name)Helper function used by GetEntity to find the resource in the primary assembly.

Example

Example 1

Visual Basic
 
Dim name As String
Dim resolver As New XmlResourceResolver(GetType(TestModule))
Dim absoluteUri As Uri = resolver.ResolveUri(Nothing, name)
Dim Input As Stream = DirectCast(resolver.GetEntity(absoluteUri, Nothing, Nothing), Stream)
Dim xslt As New XslTransform
xslt.Load(New XmlTextReader(Input), resolver, Nothing)

Source

XmlResourceResolver

Visual Basic
 
'
' Copyright © 2005, Jay B. Harlow, All Rights Reserved.
'
Option Strict On
Option Explicit On
 
Imports System.IO
Imports System.Net
Imports System.Xml
Imports System.Globalization
Imports System.Reflection
Imports System.Resources
 
 Public Class XmlResourceResolver
    Inherits XmlResolver
 
    Private ReadOnly m_assembly As [Assembly]
    Private ReadOnly m_type As Type
 
    Public Sub New(ByVal type AsType)
        m_assembly = type.Assembly
        m_type = type
    End Sub
 
    Public Overrides WriteOnly Property Credentials() As ICredentials
       Set(ByVal value As ICredentials)
           Throw New NotSupportedException
       End Set
    End Property
 
    Public Overrides Function ResolveUri(ByVal baseUri As System.Uri, ByVal relativeUri As String) As System.Uri
       If baseUri Is Nothing Then
           baseUri = New Uri(m_assembly.Location, True)
       End If
       Return MyBase.ResolveUri(baseUri, relativeUri)
    End Function
 
    Public Overrides Function GetEntity(ByVal absoluteUri As Uri, ByVal role AsString, ByVal ofObjectToReturn As Type) As Object
        Dim fullPath As String = absoluteUri.AbsolutePath
        If File.Exists(fullPath) Then
            Return New FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read)
        Else
            Dim name As String = Path.GetFileName(fullPath)
            Dim culture As CultureInfo = CultureInfo.CurrentUICulture
            Dim stream As stream
 
            ' Try the specific culture
            stream = GetManifestResourceStream(culture, name)
            ' Try the neutral culture
            If stream Is Nothing AndAlso Not culture.IsNeutralCulture Then
                stream = GetManifestResourceStream(culture.Parent, name)
            End If
            ' Try the default culture
            If stream Is Nothing Then
                stream = GetManifestResourceStream(name)
            End If
 
            If stream Is Nothing Then
               Throw New FileNotFoundException(Nothing, name)
            End If
            Return stream
        End If
    End Function
 
    Private Function GetManifestResourceStream(ByVal culture As CultureInfo, ByVal name As String) As Stream
        Try
            Dim satellite As [Assembly] = m_assembly.GetSatelliteAssembly(culture)
            Return satellite.GetManifestResourceStream(m_type, name)
        Catch ex As FileNotFoundException
            Return Nothing
        End Try
    End Function
 
    Private Function GetManifestResourceStream(ByVal name As String) As Stream
        Return m_assembly.GetManifestResourceStream(m_type, name)
    End Function
 
End Class

See Also