A very popular concept of implementing WCF services is to use a layered approach that consists of a service, a business logic and a data access layer. The dependencies between these layers might be injected at runtime via dependency injection containers.
The Service Architecture Concept Model as outlined by Don Smith proposes a WCF service facade which provides a published interface/contract that is implemented by components of a business (logic) layer. Those components have in turn dependencies with data access components of the resource access layer.
The dependencies between the layers are normally hard-coded within the service and component implementations, complicating unit tests. Pablo M. Cibraro shows how to inject component dependencies by implementing a WCF Dependency Injection Behavior. In Pablo's approach ObjectBuilder is used as the Dependency Injection Container whereas Oran Dennison makes use of Spring.NET in his approach to WCF Service Dependency Injection.
Oran presents the following setup of dependencies within his service implementation code:
[ServiceContract]
public interface IServiceContract {
[OperationContract]
...
}
public class ServiceLayer : IServiceContract {
IBusinessLogic _businessLogic;
public ServiceLayer(IBusinessLogic businessLogic) {
_businessLogic = businessLogic;
}
...
}
public interface IBusinessLogic {
...
}
public class BusinessLogic : IBusinessLogic {
IDataAccess _dataAccess;
public BusinessLogic(IDataAccess dataAccess) {
_dataAccess = dataAccess;
}
...
}
public interface IDataAccess {
...
}
public class DataAccess : IDataAccess {
...
}
The service implementation has a dependency with the business logic component, which has in turn a dependency with the data access component. The hard-wired variant of setting up all dependencies would look like this:
return new ServiceLayer(new BusinessLogic(new DataAccess()));
Dependency injection containers basically inject those dependencies by providing a mapping of interfaces to implementation classes within a configuration. This configuration might be changed at runtime, for instance in order to run unit tests that use mock implementations. Pablo explains:
Quite easy, the only requirement [for a dependency injection container] 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 {
[...]
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);
}
[...]
}
The DIInstanceProvider has then to be plugged into the dispatcher runtime by an IServiceBehavior. The type mappings are configured within a new WCF configuration section, which is implemented by a BehaviorExtensionElement that reads the mappings from the configuration file and passes them to the DIServiceBehavior instance. Pablo's sample configuration including type mappings looks like this:
<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>
Pablo has published his sample code. It should be fairly easy to adapt the code to Oran's approach or to any other dependency injection container, e.g. Castle Windsor.