Composing WCF applications

Shows how to extend a commerce application with a WCF-based service and use Dependency Injection.

This article is based on Dependency Injection in .NET by Mark Seeman, to be published Fall 2010. It is being reproduced here by permission from Manning Publications. Manning early access books and ebooks are sold exclusively through Manning. Visit the book's page for more information.
You can get an instant 40% discount on this MEAP edition by just clicking on the book cover image. Use promo code egghead40.


Windows Communication Foundation (WCF) is one of the most extensible parts of the Base Class Library (BCL). While it is fairly easy to get started writing WCF services, the myriad of extensibility points can make it hard to find just the one you need. This is also the case when it comes to DI.

NOTE

A joke claims that WCF is really an acronym for Windows Complication Foundation. There’s a certain degree of truth in that claim.

You could easily be led to believe that WCF does not support Constructor Injection. If you implement a WCF service with Constructor Injection and no default constructor, at runtime the WCF service host will throw a ServiceActivationException with a message similar to this:

The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type or pass an instance of the type to the host.

This message strongly indicates that a default constructor is required. The only way out seems to be to pass an already created instance to the WCF host. However, that raises several issues:

§ How can we do this if we host the service in Internet Information Server (IIS)?

§ This requires the service to run in a single InstanceContextMode, which is undesirable for a number of
other reasons.

The good news is that the exception message is misleading. There are other ways to enable Constructor Injection with WCF.

WCF extensibility

WCF has lots of extensibility points, but when it comes to DI we only need to know about the IInstanceProvider interface and contract behaviors. A contract behavior is a Seam in WCF that allows us to modify how a given contract (in other words, a service) behaves.

IInstanceProvider is an interface that defines how service instances are created (and released). Here is the interface definition in all its glory:

public interface IInstanceProvider
{

object GetInstance(InstanceContext instanceContext);

object GetInstance(InstanceContext instanceContext, Message message);

void ReleaseInstance(InstanceContext instanceContext, object instance);
}

The two GetInstance overloads are responsible for creating an appropriate service instance, while ReleaseInstance provides a hook for cleaning up, if necessary.

The default implementation simply looks for a default constructor on the service type, but we can replace it with one that uses DI. Figure 1 illustrates the overall flow when a hosted service receives a message.

Figure 1 When a message (request) arrives for service operation, WCF determines which CLR type will implement the service. It asks a ServiceHostFactory to create an appropriate ServiceHost that can host the requested service. The ServiceHost does its part by applying behaviors and creating the requested instance.

When you host a WCF service on IIS, a ServiceHostFactory is mandatory, although the default implementation will be used if you don’t explicitly define an alternative. If you host the service manually, a ServiceHostFactory may still be useful but is not required because you can create the appropriate ServiceHost directly in code.

When the ServiceHost applies behaviors, it picks them up from at least three different places before aggregating them:

§ Attributes

§ .config file

§ In-memory objects

While we can define behaviors in attributes, it’s not a particularly attractive strategy to use when it comes to DI because that means that we are compiling a particular creation strategy with particular Dependencies into the code. The net result is almost the same as if we had simple hard-coded the Dependencies directly in the service, just in a much more convoluted way.

A configuration file may sound like the ultimate in flexibility but really is not because it does not allow us to imperatively configure Dependencies if we should like to do that.

In-memory objects give us the best flexibility because we can choose to create the Dependencies directly in code or based on configuration settings. If we use a DI Container, we get both options for free.
This means that we should create a custom ServiceHostFactory that creates instances of a custom
ServiceHost that again can wire up the desired service with all its Dependencies.

You can create a set of general-purpose classes that do this based on your DI Container of choice or use one of the already implemented reusable container-based ServiceHostFactories. You can also create a specialized ServiceHostFactory for a particular service. Because it provides the best illustration of the process, I have chosen a specialized factory for the following example.

Example: wiring up a product management service

As an example, let us imagine that we have been asked to extend a commerce application with a WCF-based service that exposes operations that allow other applications to manage product data. This would allow us to hook up a rich client (we will do that in a subsequent section) or a batch job to manage product data.

Introducing ProductManagementService

To keep the example simple, let us assume that we wish to expose simple Create, Read, Update , and Delete (CRUD) operations. Figure 2 shows a diagram of the service and associated Data Contracts.

Figure 2 The IProductManagementService is a WCF service that defines simple CRUD operations on products. It uses the associated ProductContract and MoneyContract to expose these operations. Although not shown in this diagram, all three types are decorated with the usual WCF attributes: ServiceContract, OperationContract, DataContract, and DataMember.

Since we already have an existing domain model, we wish to implement this service by extending the domain model and expose its operations through this WCF contract. The exact details are not important ; just note that we expand the abstract ProductRepository class.

The domain model represents a product as the Entity Product, while the service contract exposes its operations in terms of the DTO ProductContract. To map between these two different types, we also introduce an interface called IContractMapper.

Entity vs. DTO

In the previous paragraph I just threw some more jargon at you, but let ’s briefly review what is meant by Entity and DTO.

An Entity is a term from Domain-Driven Design1 that covers a Domain Object that has a long-term identity unrelated to a particular object instance. This may sound abstract and theoretical, but it just means that it represents an object that lives beyond arbitrary bits in memory. While any .NET object instance has an in -memory address (identity), an Entity has an identity that lives across process lifetimes. We often use databases and primary keys to identify Entities and ensure that we can persist and read them even if the host computer reboots.

The Domain Object Product is an Entity because the concept of a product has a much longer lifetime than a single process and we use a Product ID to identify it in the ProductRepository.

A Data Transfer Object2 (DTO), on the other hand, exists only for the purpose of being transferred from one application tier to another. While an Entity may encapsulate a lot of behavior, a DTO is just a structure of data without behavior.

When exposing a Domain Model to external systems, we often do it with services and DTOs since we can never be sure that the other system can share our type system (it may not even use .NET). In such situations, we always need to map between the Entities and the DTOs.

The bottom line is that we end up with a service implementation with two Dependencies, and since both are mandatory we wish to use Constructor Injection. Here is the service’s constructor signature:

public ProductManagementService(ProductRepository repository, IContractMapper mapper)

So far we have been happily ignoring the elephant in the room: how do we get WCF to correctly wire up an instance of ProductManagementService?

Wiring up ProductManagementService in WCF

As illustrated in figure 1, the Composition Root in WCF is the triplet of ServiceHostFactory, ServiceHost and IInstanceProvider. To wire up a service with Constructor Injection, we must supply custom implementations of all three.

TIP

You can write completely reusable implementations that wrap your favorite DI Container in those three types and use it to implement IInstanceProvider. Many people have already done that, so you can probably find a readymade set for your chosen DI Container.

NOTE

In this example, I implement a hardwired container using Poor Man’s DI. I have chosen to encapsulate the hardcoded dependencies in a custom container class to give you a good idea about how you could create a reusable solution based on a particular DI Container.

1 Evans, Eric. Domain-Driven Design. Tackling Complexity in the Heart of Software. Addison-Wesley, 2004. p. 89. 2 Fowler, Martin, et al. Patterns of Enterprise Application Architecture. Addison-Wesley, 2003. p. 401.

Let us start with the custom ServiceHostFactory, which is our true entry point to a WCF service. Listing 1 shows the implementation.

Listing 1 Custom ServiceHostFactory

public class CommerceServiceHostFactory : #1

ServiceHostFactory #1

{

private readonly ICommerceServiceContainer container;

public CommerceServiceHostFactory()

{

this.container = #2

new CommerceServiceContainer(); #2

}

protected override ServiceHost CreateServiceHost( #A

Type serviceType, Uri[] baseAddresses) #A

{

if (serviceType == typeof(ProductManagementService))
{

return new CommerceServiceHost( #3

this.container, #3

serviceType, baseAddresses); #3

}

return base.CreateServiceHost(serviceType, baseAddresses);

}

}

#1 Derive from ServiceHostFactory
#2 Create container instance

#A Override CreateServiceHost
#3 Create custom ServiceHost

The custom CommerceServiceHostFactory derives from ServiceHostFactory (#1) with the single purpose of wiring up ProductManagementService instances. It will use a custom CommerceServiceContainer to do the actual work, so it creates an instance of the container in its constructor (#2). You can easily expand this example to use a true DI Container by simply creating and configuring an instance of that container instead.

When asked to create a ServiceHost, it returns a new CommerceServiceHost with the configured container (#3) if the requested service type is appropriate.

The CommerceServiceHost is responsible for assigning appropriate behaviors to all the service types it hosts. In our case, we only want to add a single behavior that assigns the desired IInstanceProvider to the services. All this work we can accomplish in the constructor shown in listing 2, and the base class will take care of the rest for us.

Listing 2 Custom ServiceHost

public class CommerceServiceHost : ServiceHost #1

{

public CommerceServiceHost(ICommerceServiceContainer container,
Type serviceType, params Uri[] baseAddresses)

: base(serviceType, baseAddresses)

{

if (container == null) #A

{ #A

throw new #A

ArgumentNullException("container"); #A

} #A

var contracts = #2

this.ImplementedContracts.Values; #2

foreach (var c in contracts) #2

{

var instanceProvider = #3

new CommerceInstanceProvider( #3

container); #3

c.Behaviors.Add(instanceProvider); #4

}

}

}

#1 Derive from ServiceHost
#A Guard Clause

#2 Loop over contracts

#3 Create InstanceProvider

#4 Add InstanceProvider as behavior

The CommerceServiceHost class derives from ServiceHost (#1), which is a concrete class that does all the heavy lifting for us.

In most cases, we will only host a single service type (in this particular case, ProductManagementService) but we are allowed to host multiple services, which means that we must add the IInstanceProvider to them all. The ImplementedContracts property is a dictionary so we must loop over its Values (#2) to target them all.

For each service type, we initialize a new instance of the custom CommerceInstanceProvider class with the container (#3). Since it doubles as a behavior, we can add it to the service’s Behaviors (#4).

The last part of our custom WCF triplet is the CommerceInstanceProvider that doubles as both IInstanceProvider and IContractBehavior. It’s a very simple implementation but, since it implements two different interfaces with complex signatures, it can look a bit daunting if you see it in one go. I will rather show the code a little at a time, but figure 3 provides an overview.

Figure 3 CommerceInstanceProvider implements both IInstanceProvider and IContractBehavior, so we are required to implement seven methods, although we can leave three empty and the other four as one-liners.

Listing 3 shows the class declaration and the constructor. Nothing much goes on here apart from the use of Constructor Injection to inject the container. Normally, we use Constructor Injection to announce to a DI Container that a class requires some Dependencies, but here it is backwards as we inject the container itself. This is normally a big code smell since it usually indicates intent to use the Service Locator anti-pattern, but it is necessary here since we are implementing the Composition Root.

Listing 3 CommerceInstanceProvider class declaration and constructor

public partial class CommerceInstanceProvider :

IInstanceProvider, IContractBehavior #1

{

private readonly ICommerceServiceContainer container; #2

#2

public CommerceInstanceProvider( #2

ICommerceServiceContainer container) #2

{ #2

if (container == null) #2

{ #2

throw new ArgumentNullException("container"); #2

} #2

#2

this.container = container; #2

} #2

}

#1 Implement WCF interfaces
#2 Constructor Injection

The CommerceInstanceProvider implements both IInstanceProvider and IContractBehavior (#1). We supply the container through standard Constructor Injection (#2). In this sample, we use the custom CommerceServiceContainer. However, replacing it with a general-purpose DI Container is a trivial exercise.

The IInstanceProvider implementation in listing 4 is used by the WCF runtime to create instances of the ProductManagementService class.

Listing 4 IInstanceProvider implementation

public object GetInstance(InstanceContext instanceContext, Message message)
{

return this.GetInstance(instanceContext); #A

}

public object GetInstance(InstanceContext instanceContext)
{

return this.container #1

.ResolveProductManagementService(); #1

}

public void ReleaseInstance(InstanceContext instanceContext,
object instance)

{

this.container.Release(instance); #2

}

#A Delegate to overload

#1 Use container to resolve
#2 Ask container to release

The WCF runtime invokes one of the GetInstance methods to get an instance of the requested service type, so we simply ask the container to wire up the ProductManagementService (#1) with all its required Dependencies.

When the service operation has completed, the WCF runtime is nice to ask us to release the instance, and once again we delegate this work to the container (#2).

The other part of CommerceInstanceProvider is the IContractBehavior implementation. The only reason we implement this interface is to allow us to add it to the list of behaviors as shown in listing 2. All of the methods on the IContractBehavior interface return void, so we can leave most of them empty as we do not need to implement them.

Listing 5 shows the implementation of the only method we care about.

Listing 5 Core implementation of IContractBehavior

public void ApplyDispatchBehavior(

ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)

{

dispatchRuntime.InstanceProvider = this; #1

}

#1 Tell the runtime about this

We only need to do one exceedingly simple thing in this method. The WCF runtime calls this method and passes an instance of DispatchRuntime, which allows us to tell it that it should be using this particular IInstanceProvider implementation (#1). Recall that CommerceInstanceProvider also implements IInstanceProvider. The WCF runtime now knows which IInstanceProvider to use and it can subsequently invoke the GetInstance method shown in listing 4.

This seems like a lot of code to implement to enable DI for WCF and I have even yet to show you the implementation of CommerceServiceContainer.

TIP

Remember that you can easily write reusable versions of these three classes that wrap your favorite DI Container and package that implementation into a library. Many developers have already done that, so you can likely find a suitable ready-made library on the internet.

The container is the last piece of the WCF DI puzzle.

Implementing the specialized container

The CommerceServiceContainer is a specialized container with a single purpose of wiring up the ProductManagementService class. Recall that this class requires instances of ProductRepository and IContractMapper as Dependencies.

With the entire WCF infrastructure out of the way, the container is free to concentrate on wiring up the dependency graph.

NOTE

Besides adhering nicely to the Single Responsibility Principle, this separation of concerns should give you a good idea that you can replace this specialized container with a general-purpose DI Container because there’s no WCFspecific code present.

The ResolveProductManagementService method wires up the instance with Poor Man’s DI as shown in listing 6.

Listing 6 Resolving ProductManagementService

public IProductManagementService ResolveProductManagementService()
{

string connectionString = #1

ConfigurationManager.ConnectionStrings #1

["CommerceObjectContext"].ConnectionString; #1

ProductRepository repository = #2

new SqlProductRepository(connectionString); #2

IContractMapper mapper = new ContractMapper(); #3

return new ProductManagementService(repository, #4

mapper); #4

}

#1 Get connection string from config
#2 Create product repository
#3 Create contract mapper
#4 Return service

In a sense, when it comes to resolving a dependency graph, it often pays to work our way backwards. We know we need to return an instance of ProductManagementService with ProductRepository and IContractMapper instances (#4). The IContractMapper instance is easy to create (#3), but the ProductRepository requires a bit more work.

We wish to use SqlProductRepository (#2), but to do that we need a connection string that we can read from the web.config file (#1).

If you wish to host the service in your own application, you can now do that by creating a new instance of the CommerceServiceHostFactory class and invoke its CreateServiceHost method with the correct parameters. It will return a CommerceServiceHost instance that you can open and it will figure out the rest for you and host the ProductManagementService.

If, however, you wish to host the service on IIS, there’s one more step that you must take.

Hosting ProductManagementService on IIS

On IIS, we do not manually create new instances of CommerceServiceHostFactory. Instead, we must tell IIS to do it on our behalf. This can be done in an .svc file by supplying the Factory attribute:

<%@ ServiceHost Factory = "Ploeh.Samples.CommerceService.CommerceServiceHostFactory, [CA]Ploeh.Samples.CommerceService"

Service = "Ploeh.Samples.CommerceService.ProductManagementService"

%>

This .svc file instructs IIS to use CommerceServiceHostFactory every time it needs to create an instance of the ProductManagementService class. It is a requirement that the ServiceHostFactory in question has a default constructor, but this is also the case in this example.

Enabling DI in WCF is harder than it should be, but at least it is possible and the end result is entirely satisfactory. We can use whichever DI Container we would like and we end up having a proper Composition Root.

Summary

Object Composition is one of three important dimensions of DI (the others being Lifetime Management and Interception). Some frameworks make it easy for us. When writing console applications and Windows clients (WPF or Windows Forms), we are more or less in direct control of what is happening at the application’s entry point. This provides us with a distinct and easily implemented Composition Root right at the entry point.

Other frameworks like ASP.NET MVC or WCF make us work a little harder, but they still provide the Seams we can use to define how the application should be composed. In WCF, the Seam almost appears as if it is accidentally there. Although it is somewhat more roundabout than implementing a single interface, we can still achieve all the DI goodness we could wish for.

By Peter Bromberg   Popularity  (2946 Views)