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.
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.
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.
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:
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.
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.
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.