Build Loosely Coupled Silverlight Applications

Dependency injection and IoC containers offer a solution

In Simplify Silverlight Data Binding in Nested Controls, I discussed how you could use the Model-View-ViewModel (MVVM) pattern to build flexible Silverlight applications that separate UI screens from code that retrieves and processes data. The MVVM pattern allows Views (the UI screens) to bind to ViewModel classes. ViewModel classes can retrieve data directly by calling a back-end service or by delegating the task to another class I call the Service Agent, which is responsible for accessing data from the Model layer. Figure 1 shows an example of the main players in the MVVM pattern, including the Service Agent. 

Typically, the Service Agent uses a proxy object to retrieve data from a WCF Service or from WCF RIA Services. Once the data is retrieved, it can be assigned to properties defined in the ViewModel, then bound to a View.

By looking through the different parts in Figure 1, you may conclude that this application is loosely coupled and already separates the different "concerns" (often referred to as Separation of Concerns or SoC). For many applications, following this simple pattern is all it takes to leverage better code reuse and to reduce maintenance costs. However, for applications that have many moving parts and that tend to change frequently, you can combine another pattern with the MVVM pattern to handle change more intelligently. Let's take a look at that pattern.

Getting Started with Dependency Injection and IoC Containers

The subject of dependency Injection (DI) and inversion of control (IoC) containers has received much attention during the past few years. Building loosely coupled applications has become more and more popular (and for good reason), especially in applications that have many dependencies that could break over time or that need to handle the addition of new modules seamlessly. My point of view falls somewhere in the middle of the overall DI usefulness spectrum. I believe that it has its place, and I use the general pattern in applications, but I also believe that it can be overused and that balance and common sense must be applied when any pattern is used.

So what is DI, and why should you, as a developer, care about it? First, DI isn't a new technology; it's simply a pattern you can use to write more loosely coupled code that can deal with change more easily. You can integrate the DI pattern into applications in several different ways. The two most popular techniques are constructor injection and setter injection (note that others exist, such as interface-based DI). Figure 2 shows an example of constructor injection.

The example constructor allows any type that implements the IOrderHandler interface to be passed. The value passed is then stored in a local field named _OrderHandler. The benefit of following this type of DI pattern is that the Customer class doesn't hard-code a reference to a specific order handler type. Instead, it allows any type to be used as long as the interface is satisfied. If the order handler type used in an application changes, it can be modified externally without touching the Customer class. Figure 3 shows how setter injection allows types to be injected into an application using properties. 

A consumer of the Customer class can create a new instance and then assign any order handler type that implements the IOrderHandler interface through the property, as follows:

Customer cust = new Customer();
cust.OrderHandler = GetOrderHandler();
//Process orders

An IoC container allows the types injected into constructors or properties to be dynamically looked up or resolved at runtime. By using an IoC container, you can define the types that an application should use in a "container" so that changes can be made in a single place. If I had to sum up DI and the purpose of IoC Containers, I'd say:

Minimize hard-coded class names when creating objects, and let IoC containers dynamically look up types and "inject" them into your application at runtime.

This means that instead of always using the "new" keyword to create object instances, you can let an IoC container look up object types and handle creating them. So, instead of doing the following:

ICustomer cust = new Customer();

you can go through an IoC container to "resolve" the object based upon the interface that's required:

ICustomer cust = MyObjectContainer.Resolve<ICustomer>();

This allows different types to be associated with the ICustomer variable and loaded behind the scenes, which leads to loosely coupled applications. The end result is that, where appropriate, your code avoids hard-coding class names in the application, allowing for more flexibility as the application grows and changes. For additional details about the concept of DI and IoC containers, read Martin Fowler's post on the subject. He provides a good introduction to constructor and setter injection, then goes into more depth.

 

Demonstrating the DI Pattern
In the remainder of this article, I'll walk you through a simple example that covers a Silverlight application my company is developing and demonstrates how using the DI pattern can help minimize code and simplify future changes. Before jumping into using an IoC container in Silverlight, let's take a quick look at the type of problem an IoC container can solve and demonstrate constructor injection. Figure 4 shows a ViewModel class that has two constructors.

Notice that the first constructor forwards a new ServiceAgent object instance to the second constructor, which accepts an IServiceAgent type. The second constructor takes advantage of constructor injection. XAML views (Silverlight pages or user controls) call this first constructor to create a ViewModel instance and access data.

Although nothing is wrong with this code, if I need to change the type of service proxy object used, I'd have to change the new ServiceAgent() line of code. Because Visual Studio provides nice search-and-replace functionality, it's easy to do that across multiple files. However, a better solution would be to define the type of service proxy object to use in one place, so it's easy to locate and easy to change, and then "inject" it into the application at runtime. I use the same two constructor signatures across many ViewModel classes in my real-world applications, so I definitely prefer this centralized code approach. Let's look at how you can use an IoC container to avoid hard-coding the new ServiceAgent() call and allow for a more loosely coupled application.

Using an IoC Container in Silverlight
You can use several different IoC containers with Silverlight; for example, Unity (included with the Prism framework), Ninject, Caliburn, and MEF (an extensibility framework that can act like an IoC container). I've always liked an IoC container named Autofac, mainly because it's very easy to use and it's a project I've followed for a while. Autofac is very flexible. You can use it in ASP.NET, Windows Forms, Windows Presentation Foundation (or any .NET application), and Silverlight applications. A specific Autofac download for Silverlight 3 (or later) is available here.

To begin, place the Autofac.dll assembly in your project's bin folder and add a reference to it by using Add Reference. Once that's done, you can create a ContainerBuilder object instance (located in the Autofac.Builder namespace) and use it to build a Container that can resolve specific types against interfaces (more on this later). For the code shown in Figure 4, this means that I can associate the ServiceAgent class with the IServiceAgent interface so that anytime I need to supply an object of type IServiceAgent, an instance of ServiceAgent will be created and passed behind the scenes. I created the class named IoCContainer, shown in Figure 5, to handle creating the Autofac ContainerBuilder and Container. 

The Build method handles creating the ContainerBuilder, which is used to associate classes with interfaces. In this case, I associate ServiceAgent with IServiceAgent by using the Register<TService>() method. This is a simple example, but keep in mind that, as needed, an application can register many associations between types and interfaces. More advanced associations can also be registered by using Autofac, including passing parameters to a resolved object's constructor. See the Autofac wiki documentation for additional details.

Once the type is registered, the ContainerBuilder object's own Build() method is called, which returns an IContainer type (a Container object that can be used to resolve an interface with an object instance). The Resolve<TService>() method added into the IoCContainer class wraps a call to the Container object's Resolve<TService>() method. It's added purely for convenience to save a little code. Although all this IoC talk may be a little intimidating at first, if you're brand-new to it, keep in mind that the code is ultimately associating the IServiceAgent interface with the ServiceAgent type. Any time the IServiceAgent inteface is resolved a new instance of ServiceAgent will be returned by the IoC container.

In the Silverlight project's App.xaml.cs file's Application_Startup event handler, I add the code shown in Figure 6, which calls the IoCContainer class's static Build() method. This officially hooks the IServiceAgent interface with the ServiceAgent type and makes it available to the Silverlight application: 

private void Application_Startup(object sender, StartupEventArgs e)

\\{

    IoCContainer.Build();

    ProcessInitParams(e.InitParams);

    this.RootVisual = new MainPage();

\\}


Once the Autofac container is initialized and built, it can be used to resolve interfaces and return corresponding object instances. Figure 7 shows an example of using the IoCContainer class from Figure 5 to create the ServiceAgent object shown earlier. 

You can see that the new ServiceAgent() code has been replaced with the IoCContainer code. If a different class needs to be used instead of ServiceAgent, a change can be made in the IoCContainer class's Build() method and all calls that need to resolve the IServiceAgent interface will automatically be updated throughout the application (which is obviously a good thing as far as maintenance goes). When this pattern is used across multiple ViewModel classes, it can result in a much more loosely coupled application that can change out Service Agent types easily as needed.

It's Only the Beginning
You can do much more with DI and IoC containers; this article has only scratched the surface. However, you should have a better understanding of DI and how you can use an IoC container in a Silverlight application to keep code loosely coupled.

Although using DI and IoC containers is certainly not required, by using them you can simplify the process of making changes to applications and enable better code reuse. Although the example shown in this article was simple, applications that reference many different types can leverage these concepts, resulting in more loosely coupled applications capable of dealing with change more easily.

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish