Chapter 7. Resources

7.1. Introduction

The IResource interface contained in the Spring.Core.IO namespace provides a common interface to describe and access data from diverse resource locations. This abstraction lets you treat the InputStream from a file and from a URL in a polymorphic and protocol-independent manner... the .NET BCL does not provide such an abstraction. The IResource interface inherits from IInputStream that provides a single property Stream InputStream. The IResource interface adds descriptive information about the resource via a number of additional properties. Several implementations for common resource locations, i.e. file, assembly, uri, are provided and you may also register custom IResource implementations.

7.2. The IResource interface

The IResource interface is shown below

public interface IResource : IInputStreamSource
{
  bool IsOpen { get; }

  Uri Uri { get; }

  FileInfo File { get; }

  string Description { get; }

  bool Exists { get; }

  IResource CreateRelative(string relativePath);
}
Table 7.1. IResource Properties
PropertyExplanation
InputStreamInherited from IInputStream. Opens and returns a System.IO.Stream. It is expected that each invocation returns a fresh Stream. It is the responsibility of the caller to close the stream.
Existsreturns a boolean indicating whether this resource actually exists in physical form.
IsOpenreturns a boolean indicating whether this resource represents a handle with an open stream. If true, the InputStream cannot be read multiple times, and must be read once only and then closed to avoid resource leaks. Will be false for all usual resource implementations, with the exception of InputStreamResource.
DescriptionReturns a description of the resource, such as the fully qualified file name or the actual URL.
UriThe Uri representation of the resource.
FileReturns a System.IO.FileInfo for this resource if it can be resolved to an absolute file path.

and the methods

Table 7.2. IResource Methods
MethodExplanation
IResource CreateRelative (string relativePath)Creates a resource relative to this resource using relative path like notation (./ and ../).

You can obtain an actual URL or File object representing the resource if the underlying implementation is compatible and supports that functionality.

The Resource abstraction is used extensively in Spring itself, as an argument type in many method signatures when a resource is needed. Other methods in some Spring APIs (such as the constructors to various IApplicationContext implementations), take a String which is used to create a Resource appropriate to that context implementation

While the Resource interface is used a lot with Spring and by Spring, it's actually very useful to use as a general utility class by itself in your own code, for access to resources, even when your code doesn't know or care about any other parts of Spring. While this couples your code to Spring, it really only couples it to this small set of utility classes and can be considered equivalent to any other library you would use for this purpose

7.3. Built-in IResource implementations

The resource implementations provided are

  • AssemblyResource accesses data stored as .NET resources inside an assembly. Uri syntax is assembly://<AssemblyName>/<NameSpace>/<ResourceName>
  • ConfigSectionResource accesses Spring.NET configuration data stored in a custom configuration section in the .NET application configuration file (i.e. App.config). Uri syntax is config://<path to section>
  • FileSystemResource accesses file system data. Uri syntax is file://<filename>
  • InputStreamResource a wrapper around a raw System.IO.Stream . Uri syntax is not supported.
  • UriResource accesses data from the standard System.Uri protocols such as http and https. In .NET 2.0 you can use this also for the ftp protocol. Standard Uri syntax is supported.

Refer to the MSDN documentation for more information on supported Uri scheme types.

7.3.1. Registering custom IResource implementations

The configuration section handler, ResourceHandlersSectionHandler, is used to register any custom IResource implementations you have created. In the configuration section you list the type of IResource implementation and the protocol prefix. Your custom IResource implementation must provide a constructor that takes a string as it's sole argument that represents the URI string. Refer to the SDK documentation for ResourceHandlersSectionHandler for more information. An example of the ResourceHandlersSectionHandler is shown below for a fictional IResource implementation that interfaces with a database.

<configuration>
  <configSections>
    <sectionGroup name="spring">

      <section name='context' type='Spring.Context.Support.ContextHandler, Spring.Core'/>

      <section name="resourceHandlers" 
               type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/>

    </sectionGroup>
  </configSections>

  <spring>

    <resourceHandlers>
      <handler protocol="db" type="MyCompany.MyApp.Resources.MyDbResource, MyAssembly"/>
    </resourceHandlers>

    <context>
      <resource uri="db://user:pass@dbName/MyDefinitionsTable"/>
    </context>

  </spring>
</configuration>

7.4. The IResourceLoader

To load resources given their Uri syntax, an implementation of the IResourceLoader is used. The default implementation is ConfigurableResourceLoader. Typically you will not need to access this class directly since the IApplicationContext implements the IResourceLoader interface that contains the single method IResource GetResource(string location). The provided implementations of IApplicationContext delegate this method to an instance of ConfigurableResourceLoader which supports the Uri protocols/schemes listed previously. If you do not specify a protocol then the file protocol is used. The following shows some sample usage.

IResource resource = appContext.GetResource("http://www.springframework.net/license.html");
resource = appContext.GetResource("assembly://Spring.Core.Tests/Spring/TestResource.txt");
resource = appContext.GetResource("https://sourceforge.net/");
resource = appContext.GetResource("file:///C:/WINDOWS/ODBC.INI");

StreamReader reader = new StreamReader(resource.InputStream);
Console.WriteLine(reader.ReadToEnd());

Other protocols can be registered along with a new implementations of an IResource that must correctly parse a Uri string in its constructor. An example of this can be seen in the Spring.Web namespace that uses Server.MapPath to resolve the filename of a resource.

The CreateRelative method allows you to easily load resources based on a relative path name. In the case of relative assembly resources, the relative path navigates the namespace within an assembly. For example:

IResource res = new AssemblyResource("assembly://Spring.Core.Tests/Spring/TestResource.txt");
IResource res2 = res.CreateRelative("./IO/TestIOResource.txt");

This loads the resource TestResource.txt and then navigates to the Spring.Core.IO namespace and loads the resource TestIOResource.txt

7.5. The IResourceLoaderAware interface

The IResourceLoaderAware interface is a special marker interface, identifying objects that expect to be provided with a IResourceLoader reference.

public interface IResourceLoaderAware
{
  IResourceLoader ResourceLoader
  {
    set;
    get;
  }
}

When a class implements IResourceLoaderAware and is deployed into an application context (as a Spring-managed object), it is recognized as IResourceLoaderAware by the application context. The application context will then invoke the ResourceLoader property, supplying itself as the argument (remember, all application contexts in Spring implement the IResourceLoader interface).

Of course, since an IApplicationContext is a IResourceLoader, the object could also implement the IApplicationContextAware interface and use the supplied application context directly to load resources, but in general, it's better to use the specialized IResourceLoader interface if that's all that's needed. The code would just be coupled to the resource loading interface, which can be considered a utility interface, and not the whole Spring IApplicationContext interface.

7.6. Application contexts and IResource paths

An application context constructor (for a specific application context type) generally takes a string or array of strings as the location path(s) of the resource(s) such as XML files that make up the definition of the context. For example, you can create an XmlApplicationContext from two resources as follows:

IApplicationContext context = new XmlApplicationContext(
	"file://objects.xml", "assembly://MyAssembly/MyProject/objects-dal-layer.xml");