(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Part 5: Developing for a multitude of clients: strategies for code reuse and keeping costs in check.

(2 votes)
Kevin Dockx
>
Kevin Dockx
Joined Nov 15, 2010
Articles:   19
Comments:   8
More Articles
1 comments   /   posted on Apr 16, 2012
Tags:   code-reuse , kevin-dockx
Categories:   Line-of-Business
Tweet

Welcome to the fifth part of this article series on strategies for designing your application for a multitude of different clients.  In the first part, we’ve looked into the business case & some general concerns, and in the second part, we made a choice for a service layer: WCF RIA Services.  In the third part, we’ve seen how we can use MEF for on demand loading & code reuse across different clients, and in the fourth part, we’ve learned how to load a multitude of assemblies on demand, and we’ve learned how we can navigate to views in an on-demand loaded assembly by implementing a custom content loader in combination with a view factory.

In this part, we’re going to add another client to equation: a Silverlight Out of Browser client.  After all the work we’ve done on the previous articles, we’ll see just how easy it is to reuse most of the code we already have.

You can download the source code for this article here (you can log in to the demo application with pete.campbell@madmen.com / abc@123).

Getting started: adding a new, Silverlight Out of Browser client

To start, we’re going to have to add a new client to our solution.  I’ve added a new Silverlight client, named SalesDashboard.Silverlight.DesktopClient, to the solution, and configured it to run as an Out of Browser application (project properties –> Silverlight).

As we’re aiming to reuse a lot of code, the Out of Browser application itself doesn’t really have to contain a lot of code: in essence, we’ll need to ensure the correct references are there, and the correct assemblies are loaded when we start the application – just like we did with the in-browser Silverlight client.

For the references, we can simply go down the same road as explained in the previous article: commonly used code, existing assemblies that contain classes used throughout the application, … are added as a reference.  This includes the MVVM Light related assemblies, Toolkit assemblies, … On the other hand, code that belongs to a specific module is loaded on demand: we do add them as references, but we set the Copy Local flag to false, ensuring they’re not copied to the output directory (and thus not packaged in the resulting XAP file, keeping file size and initial load small).

For our new client application, this results in setting the Copy Local flag to false for SalesDashboard.Client.Model (the generated model), SalesDashboard.SL.Modules.EmpOpp.ViewModels (the ViewModels from the Employee Opportunity module) and SalesDashboard.SL.Modules.EmpOpp.Views (the Views from the Employee Opportunity module) : these will be loaded when we start the application.

For demo purposes, this should result in the same application running in the browser as out of the browser, but remember: as this series is about separating out your application in modules & reusable code, nothing stops us from loading different modules in the Out of Browser application. 

But wait – if the resulting applications should be the same, and we’ve separated out as much as possible, shouldn’t we simply be able to copy/paste the code from the in-browser application?  Well, let’s try that, shall we?  Simply copy/paste the MainPage.xaml (and .cs) and App.xaml (and .cs) code into the Out of Browser application, and try to run the application. 

It compiles.  But it doesn’t run.  Although we don’t really have to change a lot – two things, actually.  Let’s look into those.

The first issue: errors when loading assemblies.

The first thing we will notice when we try to start our application is a “Type not found” error:

HeaderView is a view which is defined in an assembly we’re loading at startup: SalesDashboard.SL.Modules.EmpOpp.Views.  An error like this suggests the assembly hasn’t been loaded, so therefore, an instance of HeaderView cannot be added to the MainPage. 

If we look into what happens at application start, something immediately becomes obvious: we’re passing in a list of assemblies to load to our ParallelAsyncProcessor instance.  Code like this will try to find these assemblies in its own startup directory – that worked fine for the in-browser application (as the assemblies are deployed to the Webhosts’ ClientBin folder), but for the Out of Browser application, this isn’t sufficient anymore.  We need to pass in the exact Uri:

foreach (var dependency in lstDependencies)
{
    // note:  pass in another variable instead of directly passing in the dependency string. 
    // This ensures this new value is used when executing the parallel processes instead 
    // of using the last passed-in string multiple times 
    var foo = dependency;
    var catalogDep = new SuperDeploymentCatalog(
        new Uri("http://localhost/SalesDashboard.WebHost/ClientBin/" + foo));
    catalog.Catalogs.Add(catalogDep);
    EventHandler<AsyncCompletedEventArgs> handler = null;
    handler = (s, a) =>
    {
        parallelAsyncProcesser.ProcessComplete(foo);
        catalogDep.DownloadCompleted -= handler;
    };
    catalogDep.DownloadCompleted += handler;
    parallelAsyncProcesser.AddToParallelQueue(() => catalogDep.DownloadAsync(), foo);
}

If we now build and run the application again, we’ll see we won’t get any errors anymore.  The problem?  We don’t get anything at all anymore: just a white page, nothing more.  What’s going on?

The second issue: no more errors, but a white screen instead of an application.

To be honest, this issue actually left me quite puzzled for a while when I first ran into it.  I started looking through my code, but couldn’t find anything out of the ordinary – after all, we’re executing the exact same code as in an in-browser application.  What I did notice was that the callback handlers, used by the SuperDeploymentCatalog, didn’t return anymore: it seemed as though the requests for external assemblies were executed, but they never returned: a callback wasn’t received anymore.  I started looking around on the internet, and finally found out how this issue can be resolved: by setting the RootVisual element before loading the assemblies on-demand (not sure anymore if it was Pete Browns’ blog or Jeremy Likness’ blog where I read about this first, but both are great resources to check out).

Apparently, setting the RootVisual ensures some behind-the-screens wiring is done, so the handlers actually return, and the applications’ code continues.  I don’t find this behavior documented anywhere on MSDN – I would actually qualify this as a bug that only happens in an Out of Browser Silverlight application.

How can we solve this?  We cannot set the RootVisual to an instance of MainPage when the application loads, as that would result in composition & instantiation errors: the controls on our MainPage are defined in assemblies that are loaded on-demand.  What we can do is create an extra user control, and set that as the RootVisual when we start the application.  Afterwards, after our assemblies have been loaded, we add an instance of MainPage to that user control, as its only child (note: setting the RootVisual to a dummy control on load, and changing it to an instance of MainPage after the assemblies have been loaded doesn’t work either).

To this avail, I created a user control, MainPageHost.  This is actually a simply, empty control, which only contains a LayoutRoot element.

In Application_Startup, we set the RootVisual to an instance of MainPageHost. Once the assemblies have been loaded, I call a method on MainPageHost, LoadApplication().  This method sets the MainPageHosts’ LayoutRoot (which is a Border) child to an instance of MainPage().  This results in our application getting instantiated, which now works because all necessary assemblies have been loaded.

Code in App.xaml.cs:

parallelAsyncProcesser.AllProcessesCompleted += () =>
{
    // dependencies have been loaded, init app startpage
     (this.RootVisual as MainPageHost).LoadApplication();
};

Code in MainPageHost.xaml.cs:

internal void LoadApplication()
{
    LayoutRoot.Child = new MainPage();
}

We can now build and run our application – and everything will work as it’s supposed to work.  We’ve now created an Out of Browser client with very little effort, composing the application on-load by reusing the components we’ve separated out in the previous articles of this series.

Conclusion

In this article, we’ve seen how we can add an extra client to our solution, which reuses a lot of code from the previous articles in this series.  We’ve also learned how to work around 2 issues: passing in the correct Uri so the assemblies that have to be loaded can be found, and ensuring the necessary behind-the-screens wiring is done so the application execution can continue as expected.

What’s next?

Stay tuned for the next part of this article series, in which we’ll add a Windows Phone client to the equation!

 

About the author

Kevin Dockx lives in Belgium and works at RealDolmen, one of Belgium's biggest ICT companies, where he is a technical specialist/project leader on .NET web applications, mainly Silverlight, and a solution manager for Rich Applications (Silverlight, Windows Phone 7 Series, WPF, Surface, HTML5). His main focus lies on all things Silverlight, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a Silverlight enthusiast, he's a regular speaker on various national and international events, like Microsoft Techdays in Belgium, Portugal & Finland, NDC2011, Community Day, ... Next to that, he also authored a best-selling Silverlight book, Packt Publishing's Silverlight 4 Data and Services Cookbook, together with Gill Cleeren. His blog, which contains various tidbits on Silverlight, .NET, and the occasional rambling, can be found athttp://blog.kevindockx.com/, and you can contact him on Twitter via @KevinDockx.


Subscribe

Comments

  • -_-

    Re: Part 5: Developing for a multitude of clients: strategies for code reuse and keeping costs in check.


    posted by on Sep 01, 2012 21:21

    Nice tutorials and the pics in your post is help me to apply it

    silver light now is very effective for me

    how to lose belly fat fast - lose belly fat fast

Add Comment

Login to comment:
  *      *       

From this series