All the recent User Interfaces I have built have been developed using some kind of MVC approach - be it the good old MVP (Model/View/Presenter) pattern for WebForms applications, or the recently devised MVVM (Model/View/ViewModel) pattern for WPF.
Well I recently started work on a small "pet project" using Silverlight (let's just assume for those who know me that the aforementioned pet is a Horse) and some of my development seems to have been spent building shared components which could be used in other projects. For example, I have previously blogged about my Command Implementation for Silverlight which I am using in this project.
When building MVC applications, a key piece of the developer's strategy is the ability to abstract a class's dependencies into an external component which will resolve those dependencies at runtime into what is required by the application. This allows (for one thing) the developer to build each class without worrying too much about where that class obtains its dependencies from. Note that classes which resolve other class's dependencies at runtime (a technique known as Dependency Injection) are commonly known as Inversion of Control containers. I won't get into much more detail about this here and recommend reading this excellent MSDN article.
So, despite previous attempts to cross-compile the excellent Ninject IoC framework into Silverlight (see this blog post and comments) I failed to get it to run. The problem is that Silverlight implements a new security model, in which lots of framework methods (such as some of System.Reflection.Emit, and System.Threading.StackTrace) are not allowed to be executed from application code. Essentially, if you look in Reflector at the Silverlight libraries, anything marked with a [SecurityCritical] attribute will be inaccessible to any code you write. If you are interested, you can get more information about Silverlight's new security model here. Personally, I think it's a little overzealous, and I hope the restriction will be lifted somewhat as Silverlight's deployment mechanism matures - I'm not sure how it would work but I'd like to see shared libraries being built which are able to call into some of the code deemed critical. I guess that's not my call though!
Anyway, given that no container I could find out there would run on Silverlight, I set about writing my own IoC container to "free myself" from my dependencies, so to speak. I pushed my code into a small library I have named Silverstone. You can download the DLL here.
The container is implemented as a very simple static class - Silverstone.DI.IocContainer. What I am currently doing is just registering all my dependencies in the Startup method of my App.xaml.cs, as follows:
using Silverstone.DI; public partial class App : Application { public void Application_Startup(object sender, StartupEventArgs e) { // Register an instance of a concrete type MyClass against interface IMyInterface. // The instance will be passed to all constructors with parameter of type // IMyInterface and all settable properties of type IMyInterface. IocContainer.RegisterInstance<IMyInterface>(new MyClass()); // Register a concrete type against an abstract type. This means that a new // instance of the concrete type will be created every time the abstract type is // requested by either a constructor with parameter of type IMyInterface or a // settable property of type IMyInterface. IocContainer.RegisterForCreation<MyClass, IMyInterface>(); } }
That's pretty simple really! Note that you can only register the same abstract type (IMyInterface in this example) once.
When you wish to retrieve the implementation of any abstract type, it's just a simple call to Get<>();
IocContainer.Get<IMyInterface>();
Assuming that MyClass had been registered against IMyInterface in the container, the above call would actually return an instance of MyClass. Otherwise it will return null.
That's all there is to it really! Of course, the container is iterative and will walk the tree of constructors and properties on all objects as it goes. So, for example, if MyClass has a constructor with a parameter of type IMyOtherInterface, that will be requested from the container when creating the instance of MyClass. This is where the power of a container comes in - when you don't have think about all the dependencies of the dependencies of your dependencies, you can think a lot more clearly!
If anyone starts using this stuff and has any feedback, please let me know. Alternatively you can take a look at the source code which is available on the Google Code site for the project.
Have a great day
Neil
10 comments:
Very nice, I likey! Can you have configuration files with Silverlight?
Not exactly. There are ways of doing it but it's not really worth the effort.
For example you could put the configuration into a hidden input field and then use the HTML Bridge in Silverlight to load the configuration
from the field.
I don't personally see the need to have to set an IoC using a configuration file - what is the real advantage?
Neil
Thanks for posting this Neil, looks very useful. Do you have any plans to post an example using Silverstone? ie use the Ioc as well as the MVC stuff together.
Stuart.
Thanks Stuart. I hope you have some luck using it and if you have any questions please don't hesitate to ask.
Regarding more example posts, I am in the process of putting something together, which I hope to post up here soon.
Neil
Interesting post. I'm planning to support Silverlight in version 1.0 of Ninject; likely it will be more similar to the .NET compact framework build, which is also missing things like DynamicMethod and StackTrace. Stay tuned. :)
Thanks for the feedback Nate, and that's great to know! It will be nice to have a "fully featured" Ioc framework such as Ninject working under Siverlight.
Now all we need is a Mock object framework...
Neil
Thanks for that interesting post!
Your base view UserControlView uses a generic constructor. I've heard about troubles some people have with base classes other than UserControl in Silverlight 2. How can you handle that in a derived View in XAML? By using the TypeArguments?
Fred
Hi Fred
Yeah the way you need to do it is to create a "shim" class in your codebehind, such as:
public abstract class MyViewBase : UserControlView<MyViewModel>
public partial class MyView : MyViewBase, IMyView
Then in your XAML file, you can set the root element to
<MyViewBase x:Class="MyView"
You also need to add an attribute to the AssemblyInfo.cs
[assembly: XmlnsDefinition("http://schemas.microsoft.com/client/2007", "MyNamespace")]
Hope that makes sense... I will explain all this in more detail in upcoming posts
Regards
Neil
I came across Bloom a silverlight IoC container on codeplex. Looks like silverlight is finally getting the support it needs to build apps with modern practices.
Fantastic - good spot! I'll check it out.
Post a Comment