In the data world people often say that the database structure outlives any application consuming it, I suppose in the Web world it can increasingly be said that the Url will outlive any web application represented by it. In this context, nRoute is an attempt to make URLs a first class construct in Silverlight and WPF applications. Today, I've got the first release out on Codeplex, along with a sample application.

I am surely repeating myself, but below is the highlight of what is in the box today. I will go into details about each feature in a series of forthcoming posts that unfortunately will have to double-duty as some semblance of documentation, as does this post.

1. Routing Services: This is a direct port of the asp.net routing made available in .Net 3.5 release. However, in this case it deals exclusively in relative Urls and the semantics are changed in that it returns an IUrlResponse for a IUrlRequest send in.

Routing Services Overview

Normally you will not have to interface with the routing services, because you will consume services that build upon this.

2. Navigation Services: This deals exclusively in a navigation type requests/responses model that is usually consumed by some kind of a visual container. Just think of how the web works, you send a request, which is followed by a response that is consumed in a container (better known as a browser). Now, you don't really need a container to handle the response, you can consume it directly by using the NavigationService.

Navigation Services Overview
Again this is a bit low level plumbing you will normally deal with the NavigationService which is a static class and also with two build in IRouteHandler implementation that help serve the responses. The two handlers are NavigationRouteHandler and NavigationResourceHandler, let me show you the usage API for them:

// Navigation Route Handler usage
NavigationService.MapRoute(new Route("Customer/NewOrder",
    new NavigationRouteHandler(p => new DummyControl1(), u => (ISupportNavigationState)u)));

NavigationService.MapRoute(new Route("Customer/EditOrder/{OrderId}/",
    new NavigationRouteHandler(p => new DummyControl2(), u => (ISupportNavigationState)u)));

// Navigation Resource Handler usage
NavigationService.MapRoute("Images/MixLogo/", new NavigationResourceHandler("Images/MIX09Logo.xaml",
    NavigationResourceHandler.XamlLoader));

NavigationService.MapRoute("Images/2/", new NavigationResourceHandler("Images/iPhone2.jpg",
    NavigationResourceHandler.ImageControlLoader));
This is very similar to what is there is asp.net routing, basically all we are doing here is mapping an URL to a lambda expression that can initialize the responses on request. The second type of IRouteHandler shown above is the NavigationResourceHandler type, which basically makes it easy to materialize assembly resources as responses to any URLs like an image, text-file, or an xaml only file.

Again there is a higher level abstraction available for consuming the Navigation Services, please reference my forthcoming posts.

3. Action Services: This essentially is like a mapping for Urls to some handlers that work in the background. Think ICommands as a usage-model for this, basically you send in an ActionRequest that is handled by one or more IActionHandlers asynchronously off the UI thread. Usage scenarios include, fetching some data or processing some images all with the flick of an Url. Note, the action services do not produce a response, however they can issue some kind of response or signal once they are finished on the dispatcher thread.

Action Services Overview

This might seem quite weird but once you get a hang of it you will see how it really helps in usability and getting rid of the code-behind. The following is an example of registering an action and it's handler.

// We need to register an action url
ActionService.MapAction("Route 1", "Messenger/{MessengerType}/{ActionType}");

// and follow it up with by registering a handler for the action
ActionService.RegisterHandlerByRoute("Route 1", new MsnMessengerHandler());

// we can add another handler
ActionService.RegisterHandlerByRoute("Route 1", new GTalkMessengerHandler());
Here we register an action Url, we follow it up by registering two handlers that respond to the action call. Yet again, there is a higher level abstraction available for consuming the Action Services.

4. Navigation State Management: One of the thing the web is fraught with is state management (just see how bulky Viewstates can become or how complex forms handling can be), but they are core to the navigation experience that the web offers. Everyone is now familiar with back and forward semantics and my attempt to capture that is with these three interfaces:
StateSupportOverview

Ideally you will implement these interfaces in your ViewModel and when registering your Url handler you will point to how we can extract/get the ISupportNavigation interface. Note, it's use is optional.

5. Navigation Containers: When we navigate we do so in a container, and that is what these quintessentially are. However, they play the very important role of modelling different ways to navigate like a browsing with back-forward capabilities or navigating onwards only. I have four containers built in, shown below.


NavigationContainersOverview

The four objects to your right, are actual usable visual controls that reflect the models onto their left.  Below is a summary of the behaviour exhibited by the four controls:

  NavigationContentControl This is a vanilla and light-weight content control that can handle a navigation response and that's it. It offers no navigation history, events or related behaviour. Think Vanilla Light.
  NavigationContainer This is also a plain control that inherits and extends the NavigationContentControl but offers a richer model with events and hook ups at the application level. However, it stores no history, state or anything and it plainly navigates from one url to another. Think Direct and Onwards.
  BrowsingContainer This builds on the NavigationContainer and offers a web-like behaviour and state management features. So it stores a stack of back pages history and states it has been to and the forward pages you've backed-up on. Plus, like a browser the state is only stored for back or forward pages, and opening a new pages initializes a new state. Think Very Web-Like.
  StatefullContainer This one basically stores the state of the page when you leave it, and restores it when you navigate onto it. This doesn't have a stack of back or forward pages history, it keeps one list of states and applies it whenever you navigate onto the page. So simply your last state is restored once go navigate to the page. Think Good Memory.

There is a lot of detail in these controls that will require a separate post, but the point to take away is that you can easily create your own container - it's not too hard. And your custom container can exhibit whatever semantics or behaviours that suit your needs, for example you can extend these to store the state in isolated storage and instantiate it back on arrival so that the user can continue where he/she left. I assure it this is very extensible, which is why you see a lot of base classes and interfaces.

5. Application-level Integration: I describe nRoute as an application-flow framework and to fulfil those ideals I created a set of "Application" types that mirror the containers models I listed above. Think of these as application-level containers, that in effect link up with a container say on the root visual. So what does that mean, it means you set up a default container for navigation through out the application using hooks-up with the actual container. I suppose this is a bit hard to describe, until you see it in action, but below is a visual connection between the controls and the application they tie up with.

NavigationApplicationModelsOverview

I am not sure how much you can get out of these diagrams, but again the core idea is to register any container as an application-level container to which Urls can be navigated to by default - without having to specify who is going to be the handler. Please see the sample app for what this in effect means.

6. Browser Navigation Integration: This is already getting very long, but one important thing the "application-containers" also provide is Browser integration - which means deep-linking and deferring to the browser-shell for things like navigating back-forward and stuff. I have a very cool implementation, that uses the UnFocus History Keeper script but without any js files to reference etc in the HTML page as it just injects the javascript into the page. Critically, the javascript file itself is only 4KBs uncompressed, and is embedded into the assembly itself.  Like everything else you can extend this too, and for details you can look forward to a future post (so I'll skip another class diagram :).

There is so-much detail to elucidate with a framework like this, but I am perhaps poor in both explaining and documenting - still my hope is, this helps. Forthcoming will be a series of posts that will go over each aspect in detail. But as a highlight please do check out two things, one the sample application with full source code and second a post on how you can consume all this with a higher level API. Both these posts will give a richer idea of what's possible, than the plumbing thesis I just gave. Also, I would greatly appreciate any feedback on the API and usability aspect of the code, especially since this is my first open-source project.

Code at http://nRoute.codeplex.com - as of now specifically for SL2 no WPF version yet, but should work with SL3.

The la MVC routing framework I showed last week, well I have decided to call it "nRoute" (pronounced enroute). With "n" being ambiguous for either any or .net, which by some coincidence carries the suggestion to route anything or routing for .net ;)

So now that it has a name badge, let see what's under the hood:

  1. Routing Services

    The routing service is almost a direct port of the asp.net MVC routing engine. However, in this case it is relatively more generic and has a more forthright request-reply semantics. Also, we only do play with relative URLs here, that said you normally wouldn't have to interface with this directly. This falls under the Routing namespace.

  2. Navigation Services

    This builds directly atop the routing services, but offers its own set of APIs to handle navigation functionality. The interesting thing (and what I wacked my brain around a lot for) is that you can navigate against a handler (as in saying you want this thing to handle the navigation for this URL) or directly consume the navigation reply. That flexibility befits a lot of edge-cases scenarios, yet is very simple. This falls under the Navigation namespace.

  3. Navigation Containers

    I like to think navigation containers represent models for consuming navigation in different ways. They ultimately manifest as UI controls, but what they represent is different ways to navigate like a browsing with back-forward capabilities or vanilla navigating without any trace. In WPF you have something similar, but it is inherently very opaque and inflexible in this case it is relatively simple to cook up a custom container. However, you can do without them entirely. They fall under the Navigation.Containers namespace.

  4. Application-Level Integration

    One of the most wanted features in RIA apps is deep-linking, and that requires hooking with (at the application-level) a navigation container to handle URL requests. For that purpose, I want to provide a specialized Application class with accompanying navigation events, and maybe a Visual Studio template to shrink-wrap it. Also, I have modelled an asp.net like Site Map API, again for application level consumption. This is work in progress. 

  5. RoutingCommand Services

    The idea is to use URLs as signifiers of commands, kinda like the commanding pattern in WPF. I am still working on the details but I think it might useful in application-wide commanding scenarios, especially since it is loose-coupling through URLs, and like elsewhere we can also pass-in name-value parameters. Further, I am looking to support event type multi-casting, but it is still entirely on the drawing board.

  6. Re-routing Services

    The idea here to have some kind of built-in re-routing capabilities that allows you to change the URL without breaking existing links and the apps. This is just a future-proofing initiative, as it might be useful in cases where you have many independent / modular components and links need to be changed. Also work in progress.

That's a 10,000 ft overview; I hope you enjoyed the flight and the pilot informs me the code will be landing soon on Codeplex (too cheesy?)

Anyway, I am well aware that possibly by next week this could all be an elaborate road-kill courtesy Silverlight 3, but I am holding the fort till then. In any case, SL 3 will definitely have an application-level navigation framework, but my understanding is that it will be more akin to asp.net type mapping with real folder/file-path mapped one-on-one with relative URLs. Thus, the contrast it might have with nRoute will be in the same order that MVC routing has to asp.net file mapping; lets see how it figures.

One other thing is even though nRoute offers a somewhat different paradigm for application flow, it doesn't pre-empt the use for frameworks like Prism or Caliburn. In fact I would rather this be used in hand with the mentioned frameworks.

Posted by Rishi on 15-Mar-09 12:48 PM, 13 Comments

Categories: Architecture, Silverlight

In a lot of things that MVC brought (besides reminding me how much I hate classic asp) what I loved the most was the routing engine. The routing feature was beautiful because it provided for loose-coupling, whilst being structured and rich enough to be actionable. Given that, and for structural and development modularity purposes I adopted the .NET 3.5sp1 routing engine for an URL based-navigation framework for Silverlight.

Basically it works pretty much like MVC/asp.net routing, you set up the routes to yields UI Objects. In this case we pass in a relative url (like "Customer/EditOrder/39/") along with an optional name-value collection (a dictionary basically) as request parameters. You can think of the request parameters as QueryString's collection or Form's input-value collection. What you get out from the routing engine is a "NavigationResponse" type, that contains a UI Page (basically a FrameworkElement) and another name-value collection. The name-value collection in the response is a merged collection of the request name-values, plus what it parsed from the URL and any defaults name-values you had set up with the route.

The other thing I've tried is to marry navigation with the routing, particularly because Silverlight controls aren't inherently statefull as pertinent to navigation - think html pages, like when browsing a web-form and you click back, the page is rendered in a state you left it in, with some exceptions to the rule.  How we achieve this "statefulness" is with the following interfaces.

PageState

Mostly we just use the IPageNavigator interface that brings together the two base interfaces, along with a title property. Hopefully it should be self-descriptive, but IPageInitializer interface is called to initialize a page pre-displaying it. The InitializePage method takes in a name-value collection, which as you can guess comes from the routing engine's response. The IPageState interface is used to extract and inject state into a page, so when we browse forward or back the UI get's a name-value collection to help it restore it's state. It's kind of like the viewstate in concept, but you have to put the relevant state in and out yourself as the controls themselves don't collude in state management. Also one of the thing we want with M-V-VM pattern, is to manage the state in the ViewModel - these interface helps with that by separating the state management. Additionally, the routing engine is geared to take this into consideration, so in the code to plug in routes we register a route handler with the following constructor.

public NavigationRouteHandler(
	Func<ParametersDictionary, FrameworkElement> pageResolver,
	Func<FrameworkElement, IPageNavigator> navigatorResolver) 
{ 
	... 
}

Basically, it takes in two handlers, one to get a FrameworkElement for displaying in the UI and the other to get the page navigator (IPageNavigator) out for helping with the navigation.  This separation of the FrameworkElement and IPageNavigation is in recognition of the ViewModel, but it doesn't force you - so, if you don't need a IPageNavigator or don't implement the interface just pass in null. Or if your page itself implements the IPageNavigator, then return the page. All the three scenarios are shown below, which also shows how to register routes, defaults and constrains:

void SetupRoutes()
{
	// we can pass in default values in routes
    var _defaults = new ParametersDictionary();
    _defaults.Add("OrderId", -1);

	// we can also pass in constraints 
    var _constraints = new ParametersDictionary();
    _constraints.Add("OrderId", "\\w{2}");

	// here we register a route with no IPageNavigator
    RouteTable.Routes.Add("Sample1", 
		new Route("Customer/NewOrder", null,
        new NavigationRouteHandler(p => new DummyControl1(), null)));

	// here we register a route, with the page itself implementing 
	// the IPageNavigator and it also has default values passed in
    RouteTable.Routes.Add("Sample2", 
		new Route("Customer/EditOrder/{OrderId}/", _defaults,
        new NavigationRouteHandler(
			p => new DummyControl2(), u => (IPageNavigator)u)));

	// here we register a route with the page's ViewModel implementing the 
	// IPageNavigator via the DataContext and we also have constraints set
    RouteTable.Routes.Add("Sample3", 
		new Route("Customer/DeleteOrder/{OrderId}/", null, _constraints,
        new NavigationRouteHandler(
			p => new DummyControl3(), u => (IPageNavigator)(u.DataContext))));

}

This is very similar to asp.net or MVC routing, the difference being we have a custom route handler for Silverlight / WPF that implements the IRouteHandler. And if you don't like it or your setup is hooked up differently, just create your own IRouteHandler implementation and you are good to go. Essentially it has the same extensibility semantics that MVC has, and the workflow is geared towards a request-response type of setup. I hope you did notice the {OrderId} parameters in the route URL, they are parsed and included in the response's name-value collection. One omission for Silverlight is that we can't pass in anonymous types to set up constraints or default values because we can't reflect on them outside the declaring assembly.

Like I said earlier I have tried to marry routing and navigation, and so we have something called navigation containers. The containers are simply interfaces that imply a navigation model, and I have two of them build-in - one is a simple navigation container which you pass in a URL and it just returns the UI but doesn't store any history or anything. Another one is called BrowsingContainer that stores history, caches the state, and can browse forward or back. Just like everything else you can create you own containers to implement say roles-based validation on URls or extend them for deep-linking within the browser.

NavigationContainers

A benefit with these interfaces is that you can expose them through a dependency injection container, and thus loosely couple the "pages" within the app. Another important point to remember is that you route against or rather navigate in a container even though the routes are registered statically/globally - this means we can have two or more navigation containers controls (think WPF BrowserControl) and each will work with all the routes registered. I also use these interfaces as ViewModels for navigation container controls, so you can easily create your own custom skins with all the glitter and jazz you want - I just sampled one with the Silverlight.FX transitions. It's quite easy.

There is a lot more to say, but for now lets keep it for the future - however I am working on integrating this with Prism 2 and creating an asp.net like site map control. In the sample below do notice that the pages keep their state during back/forward navigation and their memory consumption is constrained to the loaded page (plus the saved states).  I'll put up the code later on CodePlex, it needs some scrubbing, Cheers.

Get Microsoft Silverlight

PS: I wanted to mention and thank this excellent series on MVC routing.

Posted by Rishi on 10-Mar-09 5:39 AM, 18 Comments