About the book
This is
a sample chapter of the book
Dependency Injection in .NET. It has been published with
the exclusive
permission of Manning.
Written by: Mark Seemann
Pages: 375
Publisher: Manning
ISBN: 9781935182504
Get 40% discount
DotNetSlacker readers can get 40% off the full print book or
ebook at
www.manning.com using the promo code dns40 at checkout.
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.
NoteA 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:
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. DTOIn 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 Design 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 Object (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:
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.
TipYou 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.
NoteIn 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.
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
The custom CommerceServiceHostFactory derives from ServiceHostFactory 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. 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 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
The CommerceServiceHost class derives from ServiceHost, 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 to target them all.
For each service type, we initialize a new instance
of the custom CommerceInstanceProvider class with the container. 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
The CommerceInstanceProvider implements both IInstanceProvider and IContractBehavior. We
supply the container through standard Constructor Injection. 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
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 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.
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
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.
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.
TipRemember 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.
NoteBesides 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 WCF-specific code present.
The ResolveProductManagementService method wires up the instance with Poor Man’s DI as shown in listing 6.
Listing 6: Resolving ProductManagementService
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. The
IContractMapper instance is easy to create, but the ProductRepository requires a bit more work.
We wish to use
SqlProductRepository, but to do that we need a connection string that we can read from the web.config file.
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:
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.
Get 40% discount
DotNetSlacker readers can get 40% off the full print book or
ebook at
www.manning.com using the promo code dns40 at checkout.
About Manning Publications
 |
Manning Publication publishes computer books for professionals--programmers, system administrators, designers, architects, managers and others. Our focus is on computing titles at professional levels. We care about the quality of our books. We work with our authors to coax out of them the best writi...
This author has published 33 articles on DotNetSlackers. View other articles or the complete profile here.
|
You might also be interested in the following related blog posts
A Unique Silverlight Viewer for Reporting Services Aimed to Display Reports from Reporting Services in Silverlight Applications.
read more
WCF 4: Higher Default Throttling Settings for WCF Services
read more
Using FindBySubjectDistinguishedName
read more
Intersoft Solutions Releases WebUI Studio 2009 The Worlds Most Innovative Web Development Toolkit
read more
WCF defaults stifles loose coupling
read more
CodeDigest.Com Article,Codes,FAQs - April,2009
read more
Visual Studio .NET Architecture Templates
read more
Securing Applications Built on Silverlight and WCF
read more
More reminders / gotchas from the trenches with Azure
read more
Enabling Click to Communicate in Web Applications
read more
|
|
Please login to rate or to leave a comment.