Tuesday, January 31, 2012

Autofac and WCF Lifetime Issues

I am building a fairly simple WCF service and decided to use Autofac / Autofac.Integration.Wcf for (admittedly very simple) dependency injection.

I have previously used Unity, with a custom wcf scoped lifetime manager, but I have heard good things about autofac.

Setting up the WCF instance was pretty straight forward following the wiki for a IIS hosted server, and I could immediately use the service.

The next step was to configure the service instance PerCall since I don't want session management, which was also straight forward.

Finally I wanted to register a dependency for the service, which caused some confusion, partly because I was 'doing it wrong', and partly because some of the guides I had seen were wrong.

My registration is shown below, and is based on the Autofac wiki examples
var builder = new ContainerBuilder();
builder.RegisterType<WcfService>();
builder.RegisterType<BusinessService>().InstancePerLifetimeScope();
AutofacHostFactory.Container = builder.Build();

The BusinessService is scoped as InstancePerLifetimeScope, which combined with the AutofacHostFactory definition in the service host markup should generate a new instance per WCF call.

I then called AutofacHostFactory.Container.Resolve() twice in one of my service methods witht he expectation that each call to the service method would create a single new instance of BusinessService, but the two calls in the one method would return the same instance. Unfortunately this was not the case, and a single instance was reused throughout all my service method invokations.

I should have known better and had the BusinessService as a dependency to my service constructor (which was indeed a misdemeanor) BUT, it took a considerable amount of time to find out why the manual service resolution was not respecting the expected Lifetime management. As it turns out, the AutofacHostFactory.Container was not the correct container to use, and now that I think of it, I can understand why, but there is very little description over what happens in the service configuration within Autofac.

Registering the container in the AutofacHostFactory actually creates an Autofac container on the Host Factory itself, which is why the resolution returned a common instance each time, even between calls. Obvious yes, but the code to get the actual container was far less obvious. It wasn't until I saw this 'bug request' that I understood what had happened.

The Autofac service host factory registers a new container lifetime when the service is created, and the only way to get it is to obtain it from the current WCF OperationContext. In Unity this was more explicit because I implemented the Lifetime Manager myself, but in Autofac the Integration.Wcf libraries which things a little more black box, and the lack of documentation was frustrating.

Anyway, as I said, I did it wrong to begin with - adding the BusinessService as a constructor dependency resoved the dependency exactly as I originally expected, but it can definitely be confusing for a developer as they cannot call resolve() on the same container they register it (on the AutofacHostFactory in this case).

No comments:

Post a Comment