Latest Tweet:
  • Loading...

In an earlier post this week I wrote about implementing the Model-View-ViewModel pattern in the YouCard application. In this post I’m going to build on that and implement Inversion of Control Containers and the Dependency Injection pattern. Lots have been written about dependency injection, so the focus of this post will be on using dependency injection in a Silverlight context, and specifically how to implement it using the Ninject framework. For an excellent introduction to the pattern I strongly recommend Fowlers essay on the topic.

When getting into dependency injection you might get intimidated by the number of frameworks available to help you implement the pattern. It might give you the impression that dependency injection is something big and complicated, which is going to have a huge impact on how you build your software. The later might be true, but not necessary because of the framework but rather by the flexibility gained by introducing this pattern. In its simplest form dependency injection is about how you supply external dependencies to your application classes. In the previous blog post I refactored the Twitter and Flickr integration into external classes that complies with an interface. Depending on if the code was executed inside Blend or the browser I either use the real implementation, or a mock implementation providing some dummy data at design time.

Code sample 1

The problem with the above code is the coupling between the YouCardData class and the four classes implementing the IMicroBlog and IPhotoService interfaces. This high level of coupling between the view-model (YouCardData) and its external dependencies (Twitter and Flickr) makes the code less flexible. Coding against interfaces enables me to implement other services, such as a Picasa photo service, or a Tumblr micro blog service. The problem is how I get the YouCardData class to use these alternative implementations. The code is also hard to unit test as I can’t provide a mock implementation of the external services. We could refactor our code to take the external dependencies as constructor parameters like this:

Code sample 2

By doing this we allow the consumer of the YouCardData class to inject the external dependencies through the constructor. And in essence this is constructor based dependency injection, by hand. The above change gives us greater flexibility to provide alternative implementations of the services, either for testing purposes, or to provide new functionality. But there is still a problem with the code. If you want to create an instance of the class from XAML, for instance when setting the data context, a default parameter less constructor will be used. You could solve this limitation by adding an additional constructor like this:

Code sample 3 

This would solve the XAML problem, as any instance crated declaratively would use the Twitter and Flickr implementation, but for testing purposes we could provide our own mock implementation. But the solution still isn’t perfect. In the first constructor we had code to check if the class was consumed inside Blend or not. Depending on this we used different implementations of the external services. We could have kept this constructor, but instead we’re going to use an Inversion of Control container to help us build our objects.

Ninject

Lately I’ve been doing some research on UI frameworks and patterns, and many of these use some sort of dependency injection framework. The Prism-AG framework, a Silverlight port of the Composite WPF framework, uses a small dependency injection framework called DLLite. Another dependency injection ported to Silverlight is Unity, another framework from the Microsoft patterns and practices group. But my personal favorite so far is Ninject, the ninja of dependency injection. This framework caught my attention after listening to Nate Kohari in episode 5 and 6 of the AltDotNet podcast. Ninject describes itself the following way:

Ninject is a lightning-fast, ultra-lightweight dependency injector for .NET applications. It helps you split your application into a collection of loosely-coupled, highly-cohesive pieces, and then glue them back together in a flexible manner. By using Ninject to support your software's architecture, your code will become easier to write, reuse, test, and modify.

You shall feel my wrath as I rip you apart to inject my powers into you!

The footprint of the compiled framework is only 110KB, and you only need a single reference to Ninject.Core.dll too getting what you need in most scenarios. Strength of Ninject is the focus of configuration through code instead of XML. Most other IoC containers have a strong emphasis on XML based configuration of object dependencies. This has its advantages if your deployment environment varies a lot between installations, but in many cases this adds additional configuration pain.

  1. Your configuration can get more complex and verbose since you often have to write out fully qualified assembly names for each type.
  2. Its easer to break the application through simple typing mistakes.
  3. If the rules describing how to write your application together gets complex this might be hard to express through XML.

In comparison, Ninject uses a fluent interface, or sometimes referred to as "embedded domain-specific language". This lets you take advantage of the programming language to build up the wiring of your application. You can express complex rules of how the wiring should happen, and there is nothing stopping you from writing code that reads a configuration file if some of the wiring depends on user configuration.

"… There are cases where it’s easier to use program code to do the assembly. One case is where you have a simple application that’s not got a lot of deployment variation. In this case a bit of code can be clearer than separate XML file.

A contrasting case is where the assembly is quite complex, involving conditional steps. Once you start getting close to programming language then XML starts breaking down and it’s better to use a real language that has all the syntax to write a clear program.

…My advice here is to always provide a way to do all configurations easily with a programmatic interface, and then treat separate configuration file as an optional feature. – Martin Fowler"

Another cool aspect of Ninject is that it support Silverlight “out of the box”, and is not a port or a trimmed down version of a larger framework. Ninject was small to begin with.

Dependency Injection with Ninject

Adding Ninject support is fairly straight forward. The first thing we need to do is add is marking all constructors that take the dependencies, and mark it with a simple attribute.

Code sample 4

We also want to inject a persistence service into the main page view-model, the one controlling all the cards on screen. The persistence service is used to store all the users added, so that we don’t have to add them again when we come back to the application.

Code sample 5

If we use the Twitter service implementation we also want to inject a proxy URL. This is because Twitter doesn’t allow cross-domain callers and we need to proxy the request through our own server.

Code sample 6

The next thing we need to do is to wire the view-models to the services they need. In many IoC containers this is done through XML configuration, but in Ninject this is done through code and a fluent interfaces. Ninject uses a concept of modules to wire things together. One kernel (the container) can host multiple modules. For the YouCard application we need only one module.

Code sample 7

The benefit of fluent interfaces is increased readability of the code, so I’m not going to spend too much time describing the class line by line. The class derives from StandardModule, and overrides the Load method. In the Load method we set up the binding between the services and the concrete types. If you read the binding as “English”, from left to right, the binding rules should be fairly straight forward. Also worth notice is how I take advantage of configuration through code when I decide which implementation to use when the code is running inside Blend. I add a condition saying that the Twitter service should be used when executing inside the browser, while the mock service should be used from Blend.

To use the module I simply have to create a Ninject Kernel and pass it the module.

Code sample 8 

Notice how I don’t have to worry about constructing the YouCardData object. The kernel takes care of instantiating the object, and injects any dependency based on the bindings configured in the YouCardModule.

Data binding to objects built by Ninject

Now that we have configured our Ninject kernel the next challenge is getting our view-model objects out of the kernel and into the views, without breaking the design time experience in Blend. Setting the data context through code would be fairly simple. We could create the kernel in the application class, and then get it doing something like this.

Code sample 9 

That would enable us to have one kernel for the application (something you typically do). But it still wouldn’t solve how to set the data context of a user control to view-model built by Ninject, using declarative XAML code. This troubled me for a few days, and after thinking it through, trying some different approaches, and talking discussing it with Nate Kohari the solution turned out to be Service Locators. This is a different pattern used to implement Inversion of Control, and often you decide to use either service locators or dependency injection. I recommend reading the section on service locators vs. dependency injection in Fowlers essay for a good description of the pattern.

The short version of the pattern is that a service locator is a registry holding references to all the services used by your application. A class, such as the view-models in YouCard, can ask the service locator to give them an implementation of IPhotoService or ITwitterService. The big difference between service locators and dependency injection is that with SL your classes asks for an implementation, but with DI they are given an implementation (pull vs. push). Nate has blogged about how Ninject plays nicely with service locators.

"I don’t think that service locators and dependency injection are mutually exclusive; in fact, I’ve found that it can actually be very effective when used in conjunction with a dependency injection framework like Ninject. – Nate Kohari"

The service locator I’ve created for YouCard is fairly straight forward.

Code sample 10

In many cases you implement the service locator as a static class. That was not an option, as Silverlight 2 doesn’t support data binding to static classes. The way I solved this was to make a static constructor, and a private, static kernel field. The static constructor is the first thing executed in the class, before any standard constructors. The static constructor checks if we have a kernel and if not it instantiates one using module containing our binding configuration. By making the kernel field static we can ensure that we have only one instance of it in our application. The class has two instance properties that surface our view-models from the kernel, as well as a generic instance method to get any object from the container.

Before introducing dependency injection we bound our views to the view-model declaratively like this:

Code sample 11

After introducing a service locator we need to change this around a little. The first thing we do is to instantiate the service locator as an application level resource:

Code sample 12

Then for each of the views we need to change how they get their data context.

Code sample 13

Each of the views gets their view-model by data binding to properties on the service locator. The coolest thing about this approach is that we still get full Blend design time support with sample data provided through the mock services.

Conclusion

Introducing dependency injection in Silverlight isn’t any harder than in other .NET applications. The strong focus on keeping the framework light weight and extremely fast makes Ninject a perfect fit for Silverlight. However, one could argue that for a simple example like this Ninject isn’t really necessary. I could hand-write the dependency injection code inside my service locator, and eliminate the Ninject dependency, and still get the flexibility of dependency injection. On the other hand, Ninject is only 110KB (before it’s zipped into the XAP file), and isn’t going to add a lot of download weight to your application. 100KB is less than half the size of the images used as illustrations in this blog post...

Seperation of Concerns - The way of a true master

By using dependency injection you keep your code more flexible and testable, something that is just as important for Silverlight applications, perhaps even more, are UI requirements are likely to change a lot as you discover the power of Silverlight. I strongly believe in providing designers with a best possible experience inside Blend, and there is no reason for dependency injection to change that.

Thursday, July 24, 2008 11:07:24 AM (W. Europe Daylight Time, UTC+02:00)
Great... I like your article "MVC".. I also have SLUnity, the ported version of Unity for DI.
Saturday, July 26, 2008 11:23:14 AM (W. Europe Daylight Time, UTC+02:00)
Hi Jonas,

A most excellent article. Thank you! I find that people's eyes are quick to glass over once we get into DI and its complexities. I've used Spring in the past and its configuration is powerful, but often confusing. I'll be sure to check out NInject!

Øyvind
Sunday, July 27, 2008 10:57:27 PM (W. Europe Daylight Time, UTC+02:00)
Hi Jonas

Very interesting - thank you for sharing!

Just what I have been looking for.

David Roh
David Roh
Friday, September 12, 2008 11:16:03 PM (W. Europe Daylight Time, UTC+02:00)
Hi Jonas,
I am in the process of migrating a fairly complex business app across to Silverlight and your article was a great help. I agree that maintaining the Blend designer experience is a must.
My application will have multiple Modules and one thing I was hoping to be able to do was have the Modules each in their own Silverlight Library so they can be maintained separately and to stop the main project getting too large. As the ServiceLocator both references the views and is referenced by the views it seems to prevent them being separated.
I would greatly appreciate any suggestions you have for getting around this.

Cheers

Dan
Dan
Saturday, September 13, 2008 4:01:49 AM (W. Europe Daylight Time, UTC+02:00)
Hi Dan,

I see your point. By modules I assume that you want to have self-contained modules that contains entire pieces of your application (UI, Presentation Model and Data Access). If that's the case the designer who is working on the module won't have access to the ServiceLocator, which is defined as an Application Level resource in the main Silverlight project.

The Service Locator is only referenced by the View, it does only reference the Page View Models (the non visual aspect of your view).

I think for your approach you probably want to look into some kind of Composite Application framework. In June Microsoft released "Composite WCF guidance", previously known as Prism. There is already efforts to port it to Silverlight, and there is a working version available. Microsoft have also announced that Prism 2 will support Silverlight. For more information check out these links:

http://www.codeplex.com/CompositeWPFContrib/Wiki/View.aspx?title=Prism%20to%20Silverlight&referringTitle=PrismAG

http://blogs.msdn.com/dphill/archive/2008/08/31/hello-prism-2-0.aspx

http://www.isvinnovation.com/Directory/Description.aspx?EventId=452

For your problem I'm not 100% sure how to best do it. You could set the Data Context declaratively in each module. The Data Context would be the "design time stub" version,and then in the "boot strapper" application you replace the Data Context property on all your views with views loaded from the IoC container.

Good luck! :)
Wednesday, January 07, 2009 2:45:24 PM (W. Europe Standard Time, UTC+01:00)
Hi Jonas,

It's been some time since you wrote this, but a bit of preciation of your work is never to late. Right? :-)

I really liked the explanation of the Service locator pattern in this post.

A very clarifying sentence for me was this one:

"The big difference between service locators and dependency injection is that with SL your classes asks for an implementation, but with DI they are given an implementation (pull vs. push)"

Thanks,
Pål
Friday, January 09, 2009 9:28:26 AM (W. Europe Standard Time, UTC+01:00)
Hi Pål,

I'm glad you liked the article and the explanation of SL vs IoC. For me it was a good learning exercise trying to work out how to use IoC in combination with declerative DataContext.

There are cases where modules/classes might be "pulling" the IoC container, one example is Prism. They will inject an IContainerFacade into each module, and the module will then be able to call ioc.Resolve and "pull" inn any dependency they want. I think this is okay in cases where modules might need something, but it's not 100% required. In Prism you won't know if all/which modules have been loaded, and by letting each module call the IoC container they can work out if an implementation of a service is available.

I really enjoyed your intro series on IoC - recommended it to a couple of colleagues allready.
Wednesday, January 28, 2009 10:32:31 AM (W. Europe Standard Time, UTC+01:00)
Hello Jonas,

I am working on a Silverlight 2 project at the moment and I recently discovered your great blog post while I was searching for a DI framework for Silverlight. I have used Microsoft's Unity in a project where we had multiple deployment environment. I think for my current Silverlight project Unity is oversized and NInject seems to fit perfect.
Your very good article made thinks clear and pointed me in the right direction. Thanks!
Wednesday, February 18, 2009 12:23:00 PM (W. Europe Standard Time, UTC+01:00)
Thanks for brilliant article.
This explains so well how to use Ninject + SL.
2 thumbs up :)
Well done
Thursday, February 19, 2009 1:19:52 PM (W. Europe Standard Time, UTC+01:00)
Thanks for the great feedback Brandon! This kind of feedback keeps me blogging :)

- Jonas
Friday, June 26, 2009 1:44:34 PM (W. Europe Daylight Time, UTC+02:00)
Thanks for the very imformative post Jonas!

Just out of interest, what do you recommend in place of the HtmlPage.IsEnabled when working with non-Silverlight WPF apps?
Dan
Monday, June 29, 2009 7:37:31 AM (W. Europe Daylight Time, UTC+02:00)
Hi Dan,

There is actually a better check (that I discovered after I wrote this blog post) that works in Silverlight 2:

_isInDesignMode =
(null == Application.Current) ||
Application.Current.GetType() == typeof(Application);

The reason for this is that the Application (App.xaml) object is different when running in Blend than running the real app.

This blog post describes how to use it - and how to wrap it in an API that matches the WPF way of doing it:

http://blogs.msdn.com/delay/archive/2009/02/26/designerproperties-getisindesignmode-forrealz-how-to-reliably-detect-silverlight-design-mode-in-blend-and-visual-studio.aspx

This is the official WPF way of doing it: http://msdn.microsoft.com/en-us/library/system.componentmodel.designerproperties.getisindesignmode(VS.95).aspx

Silverlight 3 introduces the more obvious API DesignerProperties.IsInDesignTool to check if you're in a design tool or not :)

Thanks for the comment!
Thursday, July 16, 2009 7:46:13 PM (W. Europe Daylight Time, UTC+02:00)
How are you. Just want to say i`m glad i found this site. Help me! I find sites on the topic: Print shower curtain. I found only this - <a href="http://www.primariajegalia.ro/Members/Curtain/springmaid-shower-curtain">springmaid shower curtain</a>. I love the shower curtain, I would definitely keep it. Installing a shower curtain rod ezinearticles. Thank :mad: Zeno from Denmark.
Thursday, October 22, 2009 2:02:37 PM (W. Europe Daylight Time, UTC+02:00)
Hey Jonas, I like your facebook picture! Where d'you buy that huge tie?

Nice article :-)
simone
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, strike) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview
<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910