nRoute Resource Locator Framework (Part I)

Posted by Rishi on 04-Jan-10 4:21 AM - Comments (3)

As the name Resource Locator Framework (RLF) suggests the idea is to locate resources and functionally it's like an IoC type registry. However, it is different from a traditional IoC containers in that it allows each type of resource to put in place its own resource materialization strategy, and two it is designed to be customizable and open-ended as opposed to being internalized and closed-looped. RLF forms the basis of many open-ended features in nRoute like Services, Modules, ViewServices, ViewModels etc - so it's quite extensively used and with this post we'll have an in-depth look at its workings. Additionally, we'll follow this up with a Part II that features an how-to create and use your own custom resources, complete with the source-code.

Resourcing

Like with every IoC registry, the first step is to catalog the resources - with RLF rather than creating a single master catalog, we create individual catalog for each type of resource. As shown in the class diagram below, a resource of type T is represented by a Resource<T> singleton class, which provides a static instance via the Catalog property. The idea with the per type catalog, is to minimize contention and give each and every type of resource maximum flexibility and control.
 ResourceLocators

Within a catalog each resource is represented by an IResourceLocator instance, along with a string-based unique identifier. An IResourceLocator, as seen above, identifies the resource's unique name (ResourceName property, which is also used as the identifier), stores meta-data associated with it (ResourceMeta property), and most importantly can provide an instance of the resource (GetResourceInstance method). Generally speaking, an IResourceLocator is kind of like an individual factory for an individual resource.

With regards to the RLF workings, IResourceLocator is the key abstraction by which each type of resource (or if you require even each individual resource) can provide its own materialization strategy - because when the RLF is asked for a resource it delegates to the IResourceLocator. And within the IResourceLocator you can customize the realization of a resource, so for example with Services in nRotue its locator provides lifetime management, whereas with ViewServices its locator can go through the Visual Tree and look for a resource's visual instance, or with ViewModel's locator it can inject the ViewModel in the View - that's the flexibility that sets the RLF apart from other locators/IoC containers. Also, one can use the IResourceLocator to lazily initialize resources, as using the provided API you can either request for the resource instance or it's representative IResourceLocator instance. Resource<T> catalog, in addition to storing a string-keyed dictionary of IResourceLocator, also implements INotifyPropertyChanged to which you can subscribe for notifications when the catalog changes. It also implements an IEnumerable<string> which enumerates (actually provides a snapshot of) the resource keys currently cataloged. The catalog is thread-safe, which is why the related API also provides a TryGetResource<T> and a IsResourceRegistered<T> checker methods. Also, the Default property in Resource<T>represents the concept of a default resource, which you can retrieve without providing a resource key. Also you can earmark any resource as default, and by convention if one has not been specified then the first registered resource is the considered the default instance; plus if there is no registered resource then the Default property returns a null value.

ResourceLocatorClass

The ResourceLocator static class helps you retrieve and check for any given resource, and it also features non-generic versions of all the resource-querying functions shown above. One other point to remember about resource locators in nRoute is that within a catalog, for any individual resource or entire resource-types, you can put in your custom IResourceLocator implementation it's not locked to any predefined types.

Mapping

Given the catalogs, the next task is to enlist resources into the catalogs - for that nRoute's preferred method is to use attributes to earmark or map resources. There is an assembly-based mapping component in nRoute (described ahead), using which we catalog all resources earmarked by any MapResourceBase derived attribute. The MapResourceBase based attributes are specifically picked up for mapping, and as shown below they yield IResourceLocator instances which are then cataloged.

MappingResources

Specifically, with the MapResourceBase attribute we ask for four things - one, give us the type of resource represented by the attribute (GetResourceType method), two can we initialize the locator immediately (via the CanInitialize method, if not we put it in a pending queue and try it recursively), three is it the default resource (IsDefaultResource property), and lastly help us with an IResourceLocator instance (GetResourceLocator method). Once we have the IResourceLocator instance and resource type, we register it with the specified resource type's catalog (Resource<T>.Catalog).

MapResources

As show above, in nRoute we have various derived mapping attributes for thing like Services, Modules, View-ViewModels etc. By having more specific mapping attributes, we also capture meta-data information so for example with the MapViewService attribute we also gather the lifetime and initialization settings, and that is encapsulated into a ViewServiceMeta class which can be accessed via the IResourceLocator's ResourceMeta property. Having the metadata available within the IResourceLocator, also enables the resource locators to effect the materialization of resources.

Further, just like the many MapResourceBase derived attributes shown above, you can also create your own custom mapping attributes for any resource type. In Part II, we'll go through a step-by-step process of creating a custom mapping attribute. Additionally, as a point of extensibility you can choose to extend, replace or ignore the available mapping-attributes in nRoute and have your custom mapping attributes in play - and this should work with all existing infrastructure without change.

Cataloging

In order to catalog the mapped/earmarked resources we have an AssemblyMapper component, which when given an assembly informs (via an Observable Channel) to all interested components that an assembly is available for mapping - the interested parties can then query for specific attributes against the assembly and act upon them as they please. This is how the MapResourceBase derived attributes are mapped as soon as any assembly is passed-to the AssemblyMapper. Further, the AssemblyMapper keeps a listing of assemblies it has mapped, this way if you choose to selectively check and map resources. Also note normally you don't need to be concerned by the AssemblyMapper, as you will normally just deal with MapResourceBase based mappings.

AssemblyMapperLoader

In addition to the AssemblyMapper we also have a RemoteResourceLoader component that can download and map any DLL or XAP packaged resource - this allows you to resolve and avail remote resources at runtime. Further, like the AssemblyMapper it also keeps track of the remote resources it has loaded or is loading. Note that when a remote resource is downloaded by the RemoteResourceLoader it is automatically subjected to mapping by the AssemblyMapper.

MEF'ed in the Future

For those who know Managed Extensibility Framework (MEF) the similarities with RLF are pretty apparent, especially as MEF targets the same sweet-spot of extensible/open-ended use. However, this is incidental as RLF was made independent of MEF and indeed predates MEF's presence in Silverlight. Nonetheless, for SL4 release I am looking into an update path whereby we can carry forward most of the functionality of what is available in nRoute today, but having swapped the underpinnings to MEF. There is a lot that MEF can add in terms of features, like implicit composition, automatic re-composition and resolving of hierarchal dependencies. However, RLF and MEF don't quite functionally reconcile, specifically because RLF's capability of realizing each resource or resource-type in a custom-to-self manner.

Apart from MEF, it is possible to enhance Resource Locators to play nice with any type of IoC containers - so anything resolved by the locators will go through your specified IoC container. However, this will be one-way traffic as you wouldn't be able to resolve RLF registered resources via your IoC container (circular-dependency issues).

Summary

To sum it up I'll just recap point-wise the basics of RLF:

  • For every resource type, an individual catalog is automatically created (Resource<T>.Catalog)
  • Within a catalog, for each resource we register a representative resource locators (IResourceLocator)
  • IResourceLocator instances capture resource name, resource meta-data and also realize resource instances
  • Using MapResourceBase derived attributes, we can capture all earmarked resource locators using the built-in mapping component
  • You can create your custom MapResourceBase derived mapping attributes
  • And using the RemoteResourceLoader class you can download, resolve and avail remote resources at runtime

And in Part II, we'll put the above into practice - which I think will better enlighten the value of RLF, so do check back.

Update: Part II is up.

Comments

mikekidder
mikekidder United States
on 24-Dec-09 4:23 PM
As always, great post.. look forward to seeing Part II with an example/source.  Ironically enough, I spent the weekend going over Mike Taulty video tutorials on MEF.  As you mentioned, verify similar to MEF.  

Maybe a MEFContrib for SL4 could happen, and help get further exposure for you with NRoute and NRoute Toolkit?

Rishi
Rishi
on 25-Dec-09 12:56 PM
@mikekidder thanks and part II is already up - which I hope was quick.. Smile Alright, so ya the MEF and RLF are quite similar in intent - in fact you could consider RLF as a poor-man's version of MEF in some ways. However, now with MEF being part of SL4 it will make a lot of difference, because by default MEF becomes the lingua franca of extensibility that all SL apps/controls/components can understand. Also by using MEF one might be able to avail nRoute's Services, Modules, ViewServices etc without having a direct dependency on nRoute. That and the added features that MEF brings I think is a wining proposition.

Now I am not sure what shape MEF and RLF integration/substitution will take - my main concern is to have IResourceLocator like functionality availed either completely in or by integrating with (using ExportProviders) MEF. IResourceLocator gives me the flexibility that I've become too reliant on. Other than that I'm just concerned that taking a dependency will double the size of nRoute's footprint - but that's the stated price. With respect to MEF contrib, do you have any specific ideas on integrating MEF/RLF?

Also I've gotto see that MEF series, as in the past I've loved Mike Taulty's nuggets series - he's really good at making it to the point.  

trackback
orktane
on 03-Feb-10 11:51 PM
IObservable based Messaging Broker for Silverlight

IObservable based Messaging Broker for Silverlight

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading