Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#
Article

Dependency Injection and Windows Communication Foundation

Rate me:
Please Sign up or sign in to vote.
4.87/5 (10 votes)
7 Sep 2011CPOL5 min read 60.6K   1.2K   27   10
This article shows an alternative approach to enable Dependency Injection when working with WCF services.

Introduction

I have read a lot of articles about how to integrate your favorite IoC container with Windows Communication Foundation. All these articles have one thing in common. They all make use of the IInstanceProvider interface and create a custom implementation of this interface to hook the service container into the WCF stack. This article is going to demonstrate a different approach to the problem and hopefully we end up with a clean and reusable solution.

Background

So what is the problem here? Why do we want to use an IoC container on the server side to manage service instances?

To illustrate this, we will look into a simple example where we have this service contract.

C#
[ServiceContract]
public interface ISampleService
{
    [OperationContract]
    int Calculate(int value1, int value2);
}

Pretty simple, and we have the following implementation to go along with it.

C#
public class SampleService : ISampleService
{
    public int Calculate(int value1, int value2)
    {
        return value1 + value2;
    }
}

The SampleService class has no dependencies passed in (yet) so the only thing we need to do is create an instance of the SampleService class whenever WCF thinks appropriate. And we don't really need to to do anything to make that happen, and most of the required information is presents in the *.svc file that corresponds to our service.

ASP.NET
<%@ ServiceHost Language="C#" Debug="true" 
       Service="WcfService1.SampleService" CodeBehind="SampleService.svc.cs" %>

What we see here is information that is used to create the service instance, and the bit that I really don't like is that we need to reference our concrete implementation (SampleService) in the .svc file. I would much rather just specify the contract. And we actually can do this by routing the service request to a ServiceHostFactory that we need to implement. Then we can change it to:

ASP.NET
<%@ ServiceHost Language="C#" Debug="true" Service="WcfService1.ISampleService" 
                Factory="WcfService1.CustomServiceHostFactory"  %>

Looks better already, but what about the CustomServiceHostFactory? Well, that is pretty easy. We just need to make it create a ServiceHost and pass the service type to its constructor.

C#
public class CustomServiceHostFactory : ServiceHostFactory
{        
    protected override System.ServiceModel.ServiceHost 
              CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return base.CreateServiceHost(serviceType, baseAddresses);
    }        
}

There we have it. It should now run just fine again. Well, actually it does not. The ServiceHost class can only accept a concrete type as the service type (or a singleton object, but that is not what we are after here).

I guess putting the contract in the .svc file was not such a great idea after all. Let's change it back to the concrete class and keep the CustomServiceHostFactory for now.

And now it works just like expected again and provided that this was the scenario, an IInstanceProvider approach would have worked just fine. I'm not going to explain how to implement it as there are at least a dozen articles that takes us through that process.

But what if we wanted to pass dependencies to SampleService? Like this:

C#
public class SampleService : ISampleService
{
    private readonly ILogger _logger;

    public SampleService(ILogger logger)
    {
        _logger = logger;
    }

    public int Calculate(int value1, int value2)
    {            
        return value1 + value2;
    }
}

If we try this, we can watch it fail with the following error message:

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.

Okay, that did not work, so now what do we do? We can't pass an interface and we can't pass a concrete type without a parameterless constructor. And an IInstanceProvider won't be any good either since we still have to give the ServiceHost what it wants.

There is a way around this, and that is to add that parameterless constructor and resort to an IInstanceProvider that does property injection or constructor injection through the constructor accepting the dependency.

Wouldn't it be better to have just that one constructor and somehow make it work? Is it even possible?

A little dynamic typing

The idea here is to create a type at runtime that implements our service contract (ISampleService) and create that type so that it only contains a parameterless constructor. What we are talking about here is sort of a proxy implementation, but without the normal method interception stuff we usually see in dynamic proxies. There is actually just one thing we need to intercept here and that is when WCF needs to create an instance of our service. I started out with the following "manual" proxy implementation.

C#
public class ManualProxy : ISampleService
{
    private readonly ISampleService _target;

    public static Func<object> TargetFactory;

    public ManualProxy()
    {
        _target = (ISampleService)TargetFactory();
    }

    public int Calculate(int value1, int value2)
    {
        return _target.Calculate(value1,value2);
    }        
}

This is sort of a lazy proxy that creates its target when the proxy type itself is created. If we go back to the CustomServiceHostFactory class, we can actually test this by using this manually implemented proxy.

Oh, and before we forget. Let's change the .svc file to only reference the service contract again. Like this:

ASP.NET
<%@ ServiceHost Language="C#" Debug="true" Service="WcfService1.ISampleService" 
                Factory="WcfService1.CustomServiceHostFactory"  %>

And the CustomServiceHostFactory goes something like:

C#
public class CustomServiceHostFactory : ServiceHostFactory
{        
    protected override System.ServiceModel.ServiceHost 
              CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        ManualProxy.TargetFactory = () => new SampleService(new Logger());
        return base.CreateServiceHost(typeof(ManualProxy), baseAddresses);
    }
}

The static target factory delegate will be invoked once the ManualProxy is created and the ServiceHost is happy since we have provided a concrete class with just a parameterless constructor. We fire up the system and we have just managed to inject a dependency into our service. Sweet!! I guess we can all imagine the target factory to be calling into our service container instead of the new operator shown above.

From manual to automatic

While we have sort of solved the problem, it would be very tiresome to actually write those proxies by hand, and that actually brings us to the core of this article. How can we create those proxy types at runtime?

Actually, this is quite simple as we can use Reflection.Emit and the TypeBuilder to create a type that implements our service interface and looks pretty much like the manual proxy we just saw.

Emitting IL code at runtime takes getting used to, but essentially we can just look at ManualProxy in ILSpy and emit exactly the same code.

It should be noted that a basic understanding of IL and stack management is good to have.

What I have done is that I have created a factory class (ServiceProxyFactory) that creates a new type, implemented it, and finally assigned the target factory delegate to the type.

C#
private static Type CreateProxyType(Type serviceType, Func<object> targetFactory)
{
    TypeBuilder typeBuilder = GetTypeBuilder(serviceType);
    FieldBuilder targetFactoryField = DefineTargetFactoryField(typeBuilder);
    FieldBuilder targetField = DefineTargetField(serviceType, typeBuilder);
    ImplementParameterlessConstructor(serviceType, typeBuilder, targetFactoryField, targetField);
    ImplementMethods(serviceType, typeBuilder,targetField);
    Type proxyType =  typeBuilder.CreateType();
    AssignTargetFactory(proxyType, targetFactory);
    return proxyType;
}

The proxy types is cached using a dictionary so that we don't create proxy types for each request.

C#
public Type GetProxyType(Type serviceContractType, Func<object> targetFactory)
{
    return _proxyCache.GetOrAdd(serviceContractType, 
       s => CreateProxyType(serviceContractType,targetFactory));
}

Most of the stuff in the ServiceProxyFactory is just pretty basic and I leave it up to reader to take a closer look at it.

Just to show a little of the "IL magic", here is the code that implements each method by forwarding the method call to the underlying target:

C#
private static void ImplementMethods(Type serviceContractType, 
        TypeBuilder typeBuilder, FieldBuilder targetField)
{
    foreach (MethodInfo targetMethod in GetTargetMethods(serviceContractType))
    {
        MethodBuilder methodBuilder = GetMethodBuilder(typeBuilder, targetMethod);
        ILGenerator ilGenerator = methodBuilder.GetILGenerator();
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.Emit(OpCodes.Ldfld,targetField);
        for (int i = 1; i <= targetMethod.GetParameters().Length; ++i)
            ilGenerator.Emit(OpCodes.Ldarg, i);
        ilGenerator.Emit(OpCodes.Callvirt,targetMethod);
        ilGenerator.Emit(OpCodes.Ret); 
    }
}

What is really interesting now is to see what we can do with this code. The whole thing weighs in at approx 100 lines of code.

We can now change CustomServiceHostFactory to this:

C#
public class CustomServiceHostFactory : ServiceHostFactory
{
    private static readonly ServiceProxyFactory 
            ServiceProxyFactory = new ServiceProxyFactory();
    protected override System.ServiceModel.ServiceHost 
              CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {            
        Type serviceProxyType = ServiceProxyFactory.GetProxyType(
             serviceType, () => new SampleService(new Logger()));            
        return base.CreateServiceHost(serviceProxyType, baseAddresses);
    }        
}

Again, we have to imagine a call to the service container instead of the new operator.

As we can see, we now have full support for Dependency Injection in WCF and we don't have to worry about the restrictions we were faced with before.

Enjoy!!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Norway Norway
I'm a 39 year old software developer living in Norway.
I'm currently working for a software company making software for the retail industry.

Comments and Discussions

 
QuestionMultiple Service classes injection Pin
Ehsan Sajjad12-Mar-16 9:38
professionalEhsan Sajjad12-Mar-16 9:38 
QuestionUnity Pin
Ehsan Sajjad12-Mar-16 9:10
professionalEhsan Sajjad12-Mar-16 9:10 
QuestionIncase anyone else wants to do it selfhosting Pin
Sacha Barber8-Sep-11 6:17
Sacha Barber8-Sep-11 6:17 
QuestionCool but.... Pin
Sacha Barber8-Sep-11 3:01
Sacha Barber8-Sep-11 3:01 
AnswerRe: Cool but.... Pin
seesharper8-Sep-11 3:49
seesharper8-Sep-11 3:49 
Hi Sacha and thanks for your response.

With regards to self hosting,it is perfectly possible to use this mechanism to leverage DI in WCF services, even when doing self hosting.

The only thing you need to do is pass the service proxy type to the constructor of the service host.

The sample below shows how we can accomplish this.

[TestMethod]
public void GetProxyType_SampleService_CanBePassedToServiceHostConstructor()
{
var serviceProxyFactory = new ServiceProxyFactory();
Type serviceProxy = serviceProxyFactory.GetProxyType(typeof (ISampleService), () => new SampleService(new Logger()));
ServiceHost serviceHost = new ServiceHost(serviceProxy, new Uri(@"net.pipe://localhost/SampleService.svc"));
serviceHost.Open();
ChannelFactory<isampleservice> channelFactory = new ChannelFactory<isampleservice>(new NetNamedPipeBinding());
var client = channelFactory.CreateChannel(new EndpointAddress(@"net.pipe://localhost/SampleService.svc"));
var result = client.Calculate(2, 2);
Assert.AreEqual(4,result);
serviceHost.Close();

}

You could also use the CustomServiceHostFactory from the article directly and have that class do the work for you.

The only issue here is that you probably need to reference your service container in order to replace the new operator with a

GetInstance/GetService call to your favorite container. Since this is is likely to happen at the start of your application, this is also the only
place we see the service container. (DI vs Service locator pattern).

The goof thing about this approach is that it can be used with any container or you could even choose not to use a container and do your DI manually.

Regards

Bernhard Richter
GeneralRe: Cool but.... Pin
Sacha Barber8-Sep-11 5:25
Sacha Barber8-Sep-11 5:25 
GeneralRe: Cool but.... Pin
Sacha Barber8-Sep-11 5:28
Sacha Barber8-Sep-11 5:28 
GeneralRe: Cool but.... Pin
Sacha Barber8-Sep-11 6:10
Sacha Barber8-Sep-11 6:10 
GeneralRe: Cool but.... Pin
seesharper8-Sep-11 8:23
seesharper8-Sep-11 8:23 
GeneralRe: Cool but.... Pin
Sacha Barber8-Sep-11 19:56
Sacha Barber8-Sep-11 19:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.