Dependency injection in WCF services

Background
In Dependency Injection class dependencies are injected at runtime. For achieving this code is done for abstractions and at the runtime concrete implementation are passed/injected either by constructor/property/method injection.
For example:
In typical 3 layered architecture Business access layer depends on Data access layer. So instead of referencing concrete Data access layer objects, BAL refers to the abstraction which is DAL contracts and inject dependency for contract at the runtime. This give way to loose coupling and DAL can be replaced at any time without rebuilding BAL as we only need to write new implementation of DAL contracts.

WCF
In WCF, we write services which are consumed by client. On the server side typically 3 layered architecture is followed where in Service refers to Business layer and business layer refers to Data access layer.
As discussed in previous post  this sort of binding is hard binding and has potential drawbacks.

In WCF we need to have default constructor and cannot have parametrized constructor alone.
In order to inject dependency we can use a parametrized constructor and can implement our custom instance provider which will resolve to exact dependencies. Instance provider is responsible for creating WCF service instance, so we need to create custom behavior for instance provider and register the same with service.
Unity is used for dependency resolution in the same code.
Follow the following steps to implement same:

  1. Implement custom Instance provider:
   public class UnityInstanceProvider : IInstanceProvider  
   {  
     #region Properties  
     private readonly IUnityContainer container;  
     private readonly Type contractType;  
     #endregion  
     #region Constructors  
     public UnityInstanceProvider(IUnityContainer container, Type contractType)  
     {  
       this.container = container;  
       this.contractType = contractType;  
     }  
     #endregion  
     #region IInstanceProvider methods  
     public object GetInstance(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.Channels.Message message)  
     {  
       return GetInstance(instanceContext);  
     }  
     public object GetInstance(System.ServiceModel.InstanceContext instanceContext)  
     {  
       return container.Resolve(contractType);  
     }  
     public void ReleaseInstance(System.ServiceModel.InstanceContext instanceContext, object instance)  
     {  
       container.Teardown(instance);  
     }  
     #endregion  
   }  

   2. Implement custom service behavior for instance provider:

  public class UnityServiceBehaviour : IServiceBehavior  
   {  
     #region Constants  
     private const string METADATA_EXCHANGE_CONTRACT = "IMetadataExchange";  
     private const string UNITY_CONTAINER_NAME = "unity";  
     #endregion  
     #region Static fields  
     private static IUnityContainer container;  
     #endregion  
     #region Constructors  
     static UnityServiceBehaviour()  
     {  
       container = new UnityContainer();  
       var section = (UnityConfigurationSection)ConfigurationManager.GetSection(UNITY_CONTAINER_NAME);  
       section.Containers.Default.Configure(container);  
     }  
     #endregion  
     #region IServiceBehavior methods  
     public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)  
     {  
     }  
     public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)  
     {  
       Type serviceType = serviceDescription.ServiceType;  
       foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)  
       {  
         foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)  
         {  
           if (endpointDispatcher.ContractName != METADATA_EXCHANGE_CONTRACT)  
           {  
             endpointDispatcher.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(UnityServiceBehaviour.container, serviceType);  
           }  
         }  
       }  
     }  
     public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)  
     {  
     }  
     #endregion  
   }  

3. Implement custom behavior extension so that service behavior can be registered through behavior extensions in config.

   public class UnityServiceBehaviorExtensionElement : BehaviorExtensionElement  
   {  
     public override Type BehaviorType  
     {  
       get { return typeof(UnityServiceBehaviour); }  
     }  
     protected override object CreateBehavior()  
     {  
       return new UnityServiceBehaviour();  
     }  
   }  

 4. Register behavior extension in config file:
 <extensions>  
    <behaviorExtensions>  
     <add name="unityBehaviorExtension" type="WCFBehaviourExtensions.UnityServiceBehaviorExtensionElement, WCFBehaviourExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />  
    </behaviorExtensions>  
   </extensions>  

5. Add this in service behavior.

6. Now you need to resolve constructor defined in the WCF service to parameterized with interfaces resolving to concrete classes in config file.
For unity the configuration will look like:
  <configSections>  
   <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>  
  </configSections>  
  <startup>  
   <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />  
  </startup>  
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">  
   <typeAliases>  
    <typeAlias alias="IDAL"  type="<<Fully qualified name of DAL Contract>>, <<Name of dll>>" />  
    <typeAlias alias="DAL"  type="<<Fully qualified name of DAL concrete class>>, << Name of dll>>" />  
    <typeAlias alias="Controller"  type="<<Fully qualified name of Controller concrete class>>, <<Name of dll>>" />  
    <typeAlias alias="IController"  type="<<Fully qualified name of Controller contract>>, <<Name of dll>>" />  
    <typeAlias alias="ServiceClass"  type="<<Fully qualified name of Service Class>>, <<Name of dll>>" />  
   </typeAliases>  
   <containers>  
    <container>  
     <register type="IController" mapTo="Controller" >  
      <constructor>  
       <param name="<<ConstructorParameterName>>" >  
        <dependency/>  
       </param>  
      </constructor>  
     </register>  
     <register type="IDAL" mapTo="DAL" >  
     </register>  
     <register type="ServiceClass" mapTo="ServiceClass" >  
      <constructor>  
       <param name="<<ConstructorParameterName>>">  
        <dependency/>  
       </param>  
      </constructor>  
     </register>  
    </container>  
   </containers>  
  </unity>  

Now your service has all dependencies injected.

Happy coding!!!!

Comments

Popular posts from this blog

Inversion of control in 3 layer architecture

Singleton pattern for logger class

Consistent Response Validation - Invalid Value for types & Business Rules in Web API