WCF Dependency Injection Behavior

Many times the services are just part of a service layer interface or facade that only delegate calls to other components in lower layers, such as entity translators, business logic components, data access components or service agents that work as proxy with other systems. To clarify more this point, this is how the Patterns & Practices team envisioned  a general multi-layer architecture for .NET applications, http://blogs.msdn.com/donsmith/archive/2006/07/21/673481.aspx

When this happens, the ideal scenario to test the service code is to replace the dependencies on lower layers by mocks or stubs objects and focus our unit tests in the service code only. Fortunately, the Dependency Injection pattern comes to help us here. Oran Dennison already discussed a similar approach in this excellent post, http://orand.blogspot.com/2006/10/wcf-service-dependency-injection.html.

During the course of this post I will take a different path using the "Dependency Injection Container" sample that comes with Object Builder . This sample also includes good documentation about the supported features.

So, suppose we have a service implementation with the following dependencies:

[ServiceContract(Namespace = http://Microsoft.ServiceModel.Samples)]

public interface ICustomer

{

   [OperationContract]

   string GetFullName(string customerId);

}

 

public class CustomerService : ICustomer

{

  ICustomerBusinessComponent businessComponent;

 

  public CustomerService(ICustomerBusinessComponent businessComponent)

  {

    this.businessComponent = businessComponent;

  }

 

  public string GetFullName(string customerId)

  {

    return businessComponent.GetFullName(customerId);

  }

}

 

public interface ICustomerDataAccess

{

  string GetFullName(string customerId);

}

 

public class CustomerDataAccess : ICustomerDataAccess

{

  public CustomerDataAccess()

  {

  }

 

  public string GetFullName(string customerId)

  {

    return "FOO";

  }

}

As you can see in the code above, our service has a direct dependency with a business component, and at the same time, our business component has a dependency with another component in the data access layer. What we want to do here is to inject both dependencies at runtime using the Dependency injection pattern.

The equivalent code with the Dependency Container looks could be,

DependencyContainer container = new DependencyContainer();

 

container.RegisterTypeMapping<ICustomerBusinessComponent, CustomerBusinessComponent>();

container.RegisterTypeMapping<ICustomerDataAccess, CustomerDataAccess>();

 

CustomerService service = container.Get<CustomerService>();

Quite easy, the only requirement is the mapping, otherwise the container will not know how to create instances of the interfaces. Now, let's move forward to try configuring this in WCF using a behavior as extensibility point. WCF supports an extension called IInstanceProvider that controls the lifecycle of a WCF service instance. We will use one this provider to hook up our custom code and inject the dependencies at runtime.

public class DIInstanceProvider : IInstanceProvider

{

  private Type serviceType;

  List<TypeMapping> typeMappings;

 

  public DIInstanceProvider(Type serviceType, List<TypeMapping> typeMappings)

  {

    this.serviceType = serviceType;

    this.typeMappings = typeMappings;

  }

 

  public object GetInstance(InstanceContext instanceContext)

  {

    return GetInstance(instanceContext, null);

  }

 

  public object GetInstance(InstanceContext instanceContext, Message message)

  {

    DependencyContainer container = new DependencyContainer();

 

    foreach (TypeMapping typeMapping in this.typeMappings)

    {

      container.RegisterTypeMapping(typeMapping.TypeRequested, typeMapping.TypeToBuild);

    }

 

    return container.Get(this.serviceType);

  }

 

  public void ReleaseInstance(InstanceContext instanceContext, object instance)

  {

 

  }

}

 

The typeMapping that you can see there in the code are extensions that we are going to set up through configuration. This class basically represents a mapping between a requested type (Which usually is an interface) and the type to build by the object builder (Which usually is the concrete implementation).

public class TypeMapping

{

  private Type typeRequested;

  private Type typeToBuild;

 

  public TypeMapping(Type typeRequested, Type typeToBuild)

  {

    this.typeRequested = typeRequested;

    this.typeToBuild = typeToBuild;

  }

 

  public Type TypeRequested

  {

    get { return typeRequested; }

  }

 

  public Type TypeToBuild

  {

    get { return typeToBuild; }

  }

}

Once we have the behavior implementation, the final step is to configure it in our application. This can be done as follows,

<behaviors>

      <serviceBehaviors>

        <behavior name="Behaviors1">

          <dependencyInjection>

            <typeMappings>

              <add name="DataAccess" typeRequested="SampleService.ICustomerDataAccess, SampleService" typeToBuild="SampleService.CustomerDataAccess, SampleService"/>

              <add name="BusinessComponent" typeRequested="SampleService.ICustomerBusinessComponent, SampleService" typeToBuild="SampleService.CustomerBusinessComponent, SampleService"/>

            </typeMappings>

          </dependencyInjection>

        </behavior>

      </serviceBehaviors>   

</behaviors>

The configuration looks simple, I just mapped two interfaces to the real implementations (Which could be replaced during testing through mocks or stub objects). No additional code needed for the WCF service :-)

As a final comment, the dependency container also supports method injection (This is to inject the dependencies that are arguments of a method) and setter injections (This is to inject dependencies through property setters).

Download the complete sample from this location.

Comments

# New and Notable 212

Sunday, December 23, 2007 9:02 AM by Sam Gentile

BizTalk Services This is one way to find out that the BizTalk Services hosted at http://biztalk.net have

# Crumbs from week ending 23-12-2007 - Service Endpoint

Monday, December 24, 2007 3:27 PM by Crumbs from week ending 23-12-2007 - Service Endpoint

Pingback from  Crumbs from week ending 23-12-2007 - Service Endpoint

# WCF et l' injection de dépendances

Friday, January 04, 2008 8:21 AM by SOA & Interop @ Microsoft France

Pablo Cibraro pr&#233;sente un exemple de mise en oeuvre une injection de d&#233;pendances pour des services

# WCF et l' injection de dépendances

Friday, January 04, 2008 9:00 AM by Noticias externas

Pablo Cibraro propose une injection de dépendances pour des services WCF . L&#39;astuce consiste à modifier

# MSDN Blog Postings &raquo; WCF et l' injection de d??pendances

Friday, January 04, 2008 9:38 AM by MSDN Blog Postings » WCF et l' injection de d??pendances

Pingback from  MSDN Blog Postings  &raquo; WCF et l' injection de d??pendances

# re: WCF Dependency Injection Behavior

Monday, April 21, 2008 12:01 PM by Taras

Hello Pablo,

Has your sample code received any development ? As far as i can deduce from your code, ObjectBuilder can be used to instantiate dependency locally and use them afterwards in the WCF service. Could you please suggest how using your approach to introduce a dependency on a remote WCF service inside a local WCF service ? In other words: how your sample could look like when either CustomerBusinessComponent or CustomerDataAccess are WCF services?

Thank you.

# re: WCF Dependency Injection Behavior

Tuesday, April 22, 2008 9:44 AM by cibrax

Hi Taras,

What you do mean with development ?. It is the same approach for a service dependency, you can encapsulate the service call in a service agent component (That implements an interface), and inject that component as a dependency. Now, that Microsoft Unity was released, you can use that instead of objectbuilder.

Pablo.

# re: WCF Dependency Injection Behavior

Wednesday, April 30, 2008 12:36 PM by Yazid

Hello,

I have downloaded your code and it works like a charm. However, when I try and add the client I does not work. I am getting:

Every binding must have at least one binding element that derives from TransportBindingElement

I am sure I have my config for the client wrong. Can you split the app.config for the clinet and the service.

Thx

Yaz

# Unit tests for WCF (And Moq)

Friday, May 16, 2008 11:15 AM by Pablo M. Cibraro (aka Cibrax)

As you may know, testing WCF services is not as simple as referencing a service implementation and start

# New and Notable 212

Tuesday, December 02, 2008 7:01 PM by Sam Gentile's Blog

BizTalk Services This is one way to find out that the BizTalk Services hosted at http://biztalk.net have been updated :) WCF/Web Service Software Factory/Oslo/Neudesic I really love the new Web Services Software Factory and the Contract Modeling capabilities

# What did we learn this week? Week of 19 januari 2009 &laquo; Hungry for Knowledge

Pingback from  What did we learn this week? Week of 19 januari 2009 &laquo; Hungry for Knowledge

Leave a Comment

(required) 
(required) 
(optional)
(required)