WCF + IoC
I’m a big fan of TDD/BDD and leaning on my IoC container of choice, StructureMap (SM), to sort things out at runtime. What I’m not a huge fan of is WCF. It can be a pain to work with the .config spaghetti and it will always add complexity to any design that can do without. There are places where services are warranted and in these cases WCF is usually the prescribed tool.
When working with WCF, I typically relied on Poor Man’s DI to attain a testable service implementation while adhering to WCF’s no-arg constructor requirement. I knew there were ways to DI-enable WCF, but didn’t have the time to get it setup. That changed recently and I had the opportunity to create a library that allows me to let SM manage all my service dependencies with the help of this post from Jimmy Bogard.
WCF + IoC + NHibernate
I’m also a fan of NHibernate and the Session per Request pattern. This makes things relatively easy and safe – the biggest benefit being that you let your web application open an ISession in the beginning of a request and flush and dispose of the ISession at the end of the request. The Repositories and Application Services need only be written to accept an ISession (constructor injection is my preference) and leave the plumbing to the application. Of course this requires configuring your application to manage the ISession and setting up your Container to create the required instances.
Applying this pattern to WCF is a little trickier. Where a web application can manage this from an HttpModule or the HttpApplication (Global.asax), a WCF service may not necessarily be accessed via Http or Https. In this case, we have to manage our Sessions and dependency resolution from a totally different pipeline. For this reason we change our nomenclature from Session/Request to Session/Call – as in a WCF call that could be Net.TCP, HTTP, Named Pipes or MSMQ. To achieve this, I will build on top of the WCF IoC library described above and utilize the contextual Session extension point in NHibernate and the techniques outlined by this post on the Real Fiction blog.
Two Part Series
The solutions will be laid out in 2 blog posts. The first is this one, where I’ll build on Jimmy’s example by providing a base for the WCF NHibernate Session per Call library. The second post, StructureMap + WCF + NHibernate Part 2, is where I’ll actually extend the WCF IoC library to allow for NHibernate Session management.
Extending Jimmy’s Example
First let me say, many thanks to you Jimmy for this post. I always enjoy everything Jimmy writes – he has a great writing style that I find easy to follow. If you aren’t subscribed to Los Techies, where Jimmy blogs, I highly recommend adding it to your feeds and checking out MVC 2 in Action from Manning Press.
I extended Jimmy’s solution relatively slightly. Because I knew I was going to be adding NHibernate support, I gave the WCF extension points in this library the ability to work stand alone or to be subclassed. In this way, I won’t couple services to NHibernate that only need IoC support.
Instance Provider
In WCF, an Instance Provider is a factory that is called upon to create the instance of the service class. WCF gives us the IInstanceProvider interface for creating our own Instance Provider. Nothing too magical here, but this is where we wire in SM to create our service instance by accessing it as a Service Locator. Besides the name change, this code is directly from Jimmy’s post.
public class IocInstanceProvider : IInstanceProvider
{
private readonly Type _serviceType;
public IocInstanceProvider(Type serviceType)
{
_serviceType = serviceType;
}
public virtual object GetInstance(InstanceContext instanceContext)
{
return GetInstance(instanceContext, null);
}
public virtual object GetInstance(InstanceContext instanceContext, Message message)
{
//assumes that the SM has been configured already
return ObjectFactory.GetInstance(_serviceType);
}
public virtual void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
}
Service Behavior
Service Behaviors in WCF do exactly what the name implies – add behavior to services. In this case, we need a service behavior to tell WCF that we want to use our own IInstanceProvider implementation. The bulk of the heavy lifting is done in the ApplyDispatchBehavior method, where we set our custom IInstanceProvider to every End Point on our service.
The main difference here between my implementation and Jimmy’s is my virtual InstanceProviderCreator method used to instantiate my custom IInstanceProvider. I default to the IocInstanceProvider class shown above, but the method is virtual and can therefore be overridden by a derived Service Behavior.
public class IocServiceBehavior : IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers)
{
var cd = cdb as ChannelDispatcher;
if (cd != null)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.InstanceProvider =
InstanceProviderCreator(serviceDescription.ServiceType);
}
}
}
}
public virtual void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public virtual void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
/// <summary>
/// A Func that takes the ServiceType in the constructor and instantiates a new IInstanceProvider.
/// Defaults to an IocInstanceProvider
/// </summary>
public virtual Func<Type,IocInstanceProvider> InstanceProviderCreator
{
get
{
return (type) => new IocInstanceProvider(type);
}
}
}
Service Host
Using a custom Service Host will allow us to add the IocServiceBehavior shown above into the pipeline without needing to configure it in the .config file. In my opinion, that is a major pain and adding the custom Service Host pays for itself with that feature alone.
Once again, my implementation is almost identical to Jimmy’s with the exception of the virtual ServiceBehavior getter. This allows me to derive a custom Service Hosts that may need further modifications and add them to the DI-enabled pipeline.
public class IocServiceHost : ServiceHost
{
public IocServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
protected override void OnOpening()
{
Description.Behaviors.Add(ServiceBehavior);
base.OnOpening();
}
public virtual IocServiceBehavior ServiceBehavior
{
get
{
return new IocServiceBehavior();
}
}
}
Service Host Factory
The Service Host Factory is responsible for creating the instance of the Service Host that will eventually put an instance of the service on the wire when it is called. A custom ServiceHostFactory is used as the starting point of our WCF call pipeline extension. To sum it up as simply as possible, it looks like this:
*.SVC -> ServiceHostFactory -> ServiceHost -> ServiceBehavior -> IInstanceProvider -> Service
My implementation is once again very similar to Jimmy’s with a couple exceptions. First, I offer the virtual SvcHost property for creating an instance of a custom ServiceHost. This will again allow me to plug in a different implementation of a ServiceFactory, which I’ll utilize in my NHibernate solution. Another difference is in how I’m initializing SM. Where Jimmy shows this being done in the constructor of the ServiceHostFactory, I keep Container initialization out of the Factory and allow the application to handle it during startup.
public class IocServiceHostFactory : ServiceHostFactory
{
/// <summary>
/// Depending on the app servicehost type, the Container should be initialized during
/// startup, i.e. HttpApplication.Application_Start or
/// AppInitialize() (http://consultingblogs.emc.com/matthall/archive/2009/08/18/castle-windsor-and-non-http-protocol-wcf-services.aspx)
/// </summary>
public IocServiceHostFactory()
{
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return SvcHost(serviceType, baseAddresses);
}
/// <summary>
/// Override to create custom ServiceHost implementation. Defaults to an IocServiceHost
/// </summary>
protected virtual Func<Type, Uri[], IocServiceHost> SvcHost
{
get
{
return (t,u) => new IocServiceHost(t,u);
}
}
}
The ServiceHostFactory is referenced in code or in the markup of an .SVC file and would look like something like this.
<%@ ServiceHost Language="C#" Service="Service.DoSomethingService" CodeBehind=" Service.DoSomethingService.svc.cs" Factory="Wcf.IoC.IocServiceHostFactory, Wcf.IoC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" %>
Configuring StructureMap
I mentioned that I’m letting the application initialize StructureMap during application start up. I also mentioned that I stuck to the WCF pipeline to ensure that this solution would work for Net.TCP or HTTP hosted web sites. This raised the question – where is a common application startup? That answer came from this post from Matt Hall. If you are using IIS 7, you can utilize a static AppInitialize() method in the root App_Code directory. This method gets called at startup from services hosted in IIS or WAS.
A few caveats worth metioning:
- The class that holds the static AppInitialize() method must have a Build Action of “content”. In other words, the class should be deployed to the server as a .cs file and not compiled into the assembly. If it is compiled, I found it wouldn’t work.
- If you choose to configure StructureMap from within this method, be aware of using the TheCallingAssembly() method when telling the scan where to look for types. This won’t work here because the class is JIT compiled into its own assembly that won’t contain the other types in your service.
- For these reasons, I find it preferable to create a Bootstrapper class within my Service project and simply call it’s Initialize() method from within my AppInitialize() method.
A simple Bootstrapper example:
public static class Bootstrapper
{
public static void Initialize()
{
ObjectFactory.Initialize(cfg =>
{
cfg.AddRegistry<ProfileRegistry>();
});
}
}
A typical AppInitialize() method located in the App_Code root directory:
public static class AppInitializer
{
public static void AppInitialize()
{
Bootstrapper.Initialize();
}
}
Conclusion
We’ve now seen how to hook WCF services up to StructureMap so that it will work with any type of hosting strategy – Net.TCP to HTTP and everything in between. We’ve also seen the extension points where we can add behavior to the IoC-enabled WCF pipeline.
In Part 2, I’ll show you how to build upon the solution provided in this post to create a second library that will utilize StructureMap and NHibernate to implement a Session per Call pattern that can be easily reused – allowing developers to focus on the requirements of the application, not the Data Access plumbing.