Tuesday, September 14, 2010

Modular Silverlight Applications

So this project of mine is getting out of hand – well okay, so far it’s all simple but it needs to be split before it gets out of hand – so I started looking at how to split the code.

I wanted a solution that would allow the following;

1. Composite Silverlight modules.

2. Composite server service modules.

3. Silverlight shell and corresponding web-server shell.

To ensure loose coupling I also want the Silverlight parts to be loaded using MEF and feature UI integration based on Prism regions.

Seems reasonable enough until you start writing the code…

WCF RIA Integration

I want client/server module communications based on WCF RIA – so there will be a one-to-one match of client module and server module – this allows reuse of the WCF RIA development experience with the least amount of messing about.

The first issue with working in this way is that WCF RIA won’t find the DomainService implementations that are lurking in dynamically loaded assemblies (not to surprising to be honest) so you will need to write the code that publishes the WCF endpoints in a manner that the client modules will be able to find using the default configuration.

Thankfully a short trip on the Reflector road to see how the WCF RIA version is implemented allows us to write a variant of that code that utilises MEF to discover the available DomainServices instead of assuming that the DomainServices are only in the assemblies loaded into the current AppDomain…

Next we need a way to get the DomainService types from the server-side plugins…

Attempt #1

Place the MEF Export attribute directly on the DomainService in the server plugin assembly. This works and the wire-up code even correctly redirects calls to it with little fuss (that code actually worked first time…) however the problems begin when you have a Silverlight client application hooked up to the server project – the Export attribute is propagated to the client-side code – opps! Not required and not possible to disable either… Worse still MEF is used in the Silverlight side too so we can’t even define a dummy Export attribute!

Attempt #2

Harvest the DomainService types in a given plug-in assembly and pass this list of types to the server shell via an MEF exported class. This has none of the problems seen in the first attempt because the MEF attributes are never placed on the DomainService. The solution feels better too as exporting DomainService objects just didn’t feel right!

The only problem is the harvester class must be added to each server module project – a little code smell – alas it was the best I could come up with…

Prism Integration

From the Silverlight side, the shell is built on a heavily modified version of Prism and SilverlightFX (the two frameworks being co-joined, adapted to coexist with MEF and Unity and updated to run under Silverlight v4 – not an insignificant amount of work)

Given this platform the first thing to do is create a Prism IModuleCatalog implementation that can publish the information on the modules available on the server to the default ModuleManager.

The server knows what modules are available to it is a simple leap to create a WCF RIA DomainService in the server shell that can pass this information to the client shell. This is the ClientModuleDomainService. The information passed is much the same as that required by Prism;

  • Module name
  • Module dependencies
  • Load mode
  • Module SHA1 hash
  • Offline-Capable flag

Note: The last two fields are used to extend the OOB install experience to allow modules to be installed to a user’s computer and allow change detection. During start-up in OOB mode the shell will attempt to detect the server and if we determine the server is offline then only the offline-capable modules will be reported to Prism for loading (more on that another time.)

Conclusion

Modular WCF RIA applications are challenging with many ways of implementing a solution that depend on the specific scenario you wish to fill. In my particular case I don’t use the delayed loading feature of Prism – modularity is simply about code organisation and creating focused, loosely-coupled, testable code. Your mileage may differ…

No comments:

Post a Comment