Adding Business Services in WPF with Prism and Unity
WPF with Prism and Unity allow you to create loosely-coupled applications that assemble themselves at run time. Here's how Prism and Unity allow you to dynamically integrate business logic into your application.
In an earlier column
, I introduced WPF+Prism+Unity, which form Microsoft's recommended technology base for creating applications that assemble themselves at run-time. This technology set is all about creating loosely-coupled modules that you can update or replace without having to recompile every other part of the application. This strategy supports application development where an application is built by more than one person working in parallel, or where the application is expected to evolve over time, requiring components of it to be replaced.
In the WPF+Prism+Unity world (or Silverlight+Prism+Unity), an application begins with the Shell, which includes the user interface (a WPF window). That window displays one or more WPF User Controls. The rest of the code for the application itself is distributed over one or more Modules. In the previous article I created a Module consisting of a WPF User Control (a View) to be used in the Shell, and a class with all of the UI logic for the View (a ViewModel). What I didn't address was incorporating any non-UI business functionality: What, in "Prism-speak", is called a service. Fortunately, incorporating business logic isn't much different from incorporating UI logic.
Defining Service Modules
The first step is to define where the application will find its modules. You do that in the Shell (the start point for the application with the WPF form that forms the UI). There are a number of ways of doing that (and I'll eventually be looking at one other method, using a configuration file), but I'll stick with defining a folder in the same folder as the application's EXE. The next step is to create a second project to hold the service code and add a post-build event to the project's properties that copies the project's DLL to the folder (I described those steps in my previous column and won't drag you through them again).
The First Service Class
The new service Module project will have an initializer class (a class that Implements the IModule interface) that registers all the service classes that the module provides, using the Unity container that's passed to the initializer class's constructor. When you register a class in a container you specify the interface the class implements, the name of the relationship you're setting up between the interface and the class, and the lifetime manager you're using.
In my previous article I used the ContainerControlledLifetimeManager, which ensured that only one copy of the class would be created for the whole application. That made sense since I was loading a part of my user interface and knew that I'd only ever need one copy of the class. However, I could imagine that a service that supplies, for instance, Customer entities to the application might be created several times. So for this example, I'll use the TransientLifetimeManager, which ensures that an object is created each time it's created.
When I start building an application, I often start by creating a mock data access object that returns dummy data; this lets me test my UI interactions and workflow. So when creating my data access module, I would probably begin with a mock object that returns a fixed set of classes. This code, for instance, which I put in the Initialize method of my Module's initializer class, ties my ICustomerFactory interface to my MockCustomerFactory class using the name MockNWCustomerFactory and a TransientLifeTimeManager:
Microsoft.Practices.Unity.TransientLifetimeManager tlm =
typeof(MockCustomerFactory), "MockNWCustomerFactory", tlm);
To get this code to compile, I'll need to define the ICustomerFactory method and the MockCustomerFactory. For now, I'll just define a single method that returns all the Customers. Since I'm a big fan of data transfer objects, I define a DTO with just the Customer data that the application needs, an interface that includes a method that returns that DTO, and a mock factory object that generates some test data for me (as shown in Listing 1).
The MockCustomerFactory class itself will be one of the classes in my Module project. But that raises the question of where the files holding the DTO and the interface should be put. One choice is the Shell application, and having all the Modules add a reference to that project. A better choice is to create a separate "intfrastructure project" to hold your application's common resources. You can then add references to that project to your Shell and all of your Modules.
I'm now ready to test my application using the mock data returned by my mock class. That raises the question of where that object should be resolved -- a topic I'll address in my next column.
Peter Vogel is a principal in PH&V Information Services, specializing in ASP.NET development with expertise in SOA, XML, database, and user interface design. His most recent book ("rtfm*") is on writing effective user manuals, and his blog on technical writing can be found at rtfmphvis.blogspot.com.