I was triggered to spend some time on thinking about deeplinking, when I was listening to a podcast with Neal Ford, here.
In it, he has quite a few arguments why something like Silverlight (and Flex for that matter) will never amount to anything. I disagree with almost all of his points, but one stuck with me more: the inability to do deeplinking.
Let me start off by saying that I think the ‘normal’ html world has reached maturity and should soon begin to disappear. As almost everything in the world, technology adoption follows a wave pattern. Html has had some great advantages which made it easy to adopt. However, as computing power increases and humans become more accustomed to great applications, html as a platform does not deliver anymore. It was rejuvenated by the Ajax revolution, but in the end, you are always fighting against the restrictions that it imposes.
Those restrictions are no longer necessary. Flash did not deliver as a RIA platform, but Flex seems very capable, as does Silverlight. It will take a few years, but the demand for rich clients will drive the adoption of said technologies.
Being able to do deeplinking, is an important part of the experience and usability. The more I thought about it, the more I agreed on this. Although I think that browsers (as we know them) will cease to exist pretty soon or more likely: change to meet new needs, for the next few years we will have to deal with the restrictions they impose.
So, I started to think about how we can solve the deeplinking issue for Silverlight.
I had a flash of brilliance when I thought of the achor (#) sign in url’s. They can be navigated to, but the page is not reloaded. Exactly what was needed for deeplinking.
After doing some fast research, I discovered half the world had already thought of this trick and it is heavily used by the Flex world.
That discovery ruined my chances to score some ‘smart'-points with my girlfriend, but it won't keep me from implementing my idea 
The basic idea
The idea is to get to the url at the beginning of the application and treat everything after the # sign as 'state'. This state is used by the components in our application to initialize themselves to the correct state. For instance, show the help page, or the products page.
When a component is changed and it is important enough to reflect this change in the url, we use javascript to navigate to the new url. The browser will recognize that only the anchor has changed, and will not really browse there. However, the user can now confidently copy the url.
It's pretty easy.
Two approaches
Using a navigationcontroller.
Your application could instantiate one navigationcontroller. This controller would be used inside your application to show different usercontrols etcetera. I think such an approach is well suited for a MVC-style of application architecture.
Obviously, since all your navigation is taken care of by a central component, it would be very easy to take care of 'serializing' its state to the url.
Using per component approach.
If you're just not that kind of person, you could also just make the components you care about do the (de)serializing. So, possibly react to the Loaded event of a component and reading the url to see how to initialize it.
I've taken this a step further and created a class that serializes the vertical offset of a Scrollviewer. It can be used like so:
1 <ScrollViewer x:Name="sv1" VerticalScrollBarVisibility="Auto" Margin="10">
2 <nav:ScrollviewerOffsetStateAttacher.Register>
3 <nav:ScrollviewerOffsetState TemplateName="HelpTemplate" PartName="pos1" />
4 </nav:ScrollviewerOffsetStateAttacher.Register>
5 <TextBlock TextWrapping="Wrap">
6 Lorem ipsum dolor sit amet, conse
(pretty radical, isn't it. Here I'm serializing the amount of scrolled pixels to the url. That's something else than just which page you are viewing!)
Some more code
First off, you need to think about how the url is serialized. Some kind of template needs to be known to the system. And, different templates should be available for different parts of your application. So, during initialization of my application I do this:
NavigationState.RegisterTemplate("MainNavigationTemplate", "mainpage");
NavigationState.RegisterTemplate("ProductTemplate", "mainpage/product/detailpos");
NavigationState.RegisterTemplate("HelpTemplate", "mainpage/pos1/pos2");
A better approach might be to supply regex expressions.
As you have figured out by now, I'm using a static class 'NavigationState' to manage my url fiddling. It contains a SetNamedPartState and a GetNamedPartState method. So when I navigate to the Products page, I might do this:
appController.NavigateToPage(typeof(Products));
NavigationState.SetNamedPartState("mainpage", "ProductTemplate", "products");
I'm telling it to use the producttemplate and set the mainpage part of that template to the state 'products'.
During the load though, I do the opposite:
string state = NavigationState.GetNamedPartState("mainpage", "MainNavigationTemplate");
if (!String.IsNullOrEmpty(state))
{
if (state == "products")
ProductsSelected();
else if (state == "help")
HelpSelected();
}
Getting the url is easy:
string uri = HtmlPage.Document.DocumentUri.ToString();
Setting it is only slightly harder:
HtmlPage.Window.Eval(String.Format("window.navigate('{0}#{1}');",
NavigationApplicationString, InternalStateString));
Conclusion, work ahead
It's pretty a pretty simple idea. I like the way I attached a 'state' object to a scrollviewer control to make a no-code, designer friendly experience possible.
If someone would get serious about this, I guess they would take a look at the asp.net mvc approach. They also hook the url's you are setting, to the back button(!) So, there should be good crossbrowser javascript available.
Also, a good and flexible url parsing engine is necessary.
Finally, when you take the approach of one controller doing all the hard work, nothing much has to be done. However, I can see the creation of all kinds of specific classes that can be attached to controls to make them 'url-persistable' (think of selecting the right listbox item).
Try it out
The homepage of our sample application:
http://www.sitechno.com/silverlight/deeplinking/deeplinkingtestpage.html
Two url's with state in them:
http://www.sitechno.com/silverlight/deeplinking/deeplinkingtestpage.html#products/SqlServer/760
http://www.sitechno.com/silverlight/deeplinking/deeplinkingtestpage.html#help/309/1166
I will not keep this application available forever and probably not update it to the release version of beta2.
Who is going to make themselves useful by creating a robust solution? Leave a comment of mail me if you want the source code!