WCF 4 and Autofac IoC inside Windows Server AppFabric

I’ve  needed to use autofac recently inside WCF 4 services. Services are hosted using Windows Server AppFabric. This post is about it

Some time ago I’ve started new open-source project OnAgile. This is Agile project and task management tool that uses cutting-edge technologies ( WCF 4, Silverlight 4, NHibernate 3, Postgre SQL 9x). But thats another long and interesting story.

Once I had created basic proto for my WCF services and Silverlight client I faced with the need of IoC for my services. My first attempt was to use autofac IoC. Let’s assume we’ve got following service contract and implementation:

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        int Foo();
    }

    public class Service1 : IService1
    {
        public Service1(ICalculator calculator)
        {
            this.calculator = calculator;
        }

        #region IService1 Members

        public int Foo()
        {
            return calculator.Calculate();
        }

        #endregion

        private ICalculator calculator;
    }

As you can see our service depends on ICalculator interface. Here it is (with implementation):

    public interface ICalculator
    {
        int Calculate();
    }

    public class ConstCalculator : ICalculator
    {
        #region ICalculator Members

        public int Calculate()
        {
            return 5;
        }

        #endregion
    }

Our goal is to inject ICalculator inside  constructor of  IService1 concrete implementation (e.g. Service1). First of all let’s create custom IInstanceProvider implementation:

    public class IocInstanceProvider : IInstanceProvider
    {
        public IocInstanceProvider(Type serviceType, IContainer container)
        {
            this.serviceType = serviceType;
            this.container = container;
        }

        #region IInstanceProvider Members

        public object GetInstance(InstanceContext instanceContext, Message message)
        {
            return ResolveUnregistered(serviceType, container); // container.Resolve(serviceType);
        }

        public object GetInstance(InstanceContext instanceContext)
        {
            return GetInstance(instanceContext, null);
        }

        public void ReleaseInstance(InstanceContext instanceContext, object instance)
        {
            if (instance is IDisposable)
            {
                ((IDisposable)instance).Dispose();
            }
        }

        public object ResolveUnregistered(Type type, IContainer container)
        {
            var constructors = type.GetConstructors();
            foreach (var constructor in constructors)
            {
                try
                {
                    var parameters = constructor.GetParameters();
                    var parameterInstances = new List<object>();
                    foreach (var parameter in parameters)
                    {
                        var service = container.Resolve(parameter.ParameterType);
                        if (service == null) throw new Exception();
                        parameterInstances.Add(service);
                    }
                    return Activator.CreateInstance(type, parameterInstances.ToArray());
                }
                catch { }
            }
            throw new Exception();
        }

        #endregion

        private readonly Type serviceType;
        private readonly IContainer container;
    }

Key methods are GetInstance() and ResolveUnregistered(). First one is called when WCF runtime actually needs to create new instance of service. Second one allows to overcome autofac limitations — autofac can’t resolve unregistered types. I’ll cover why this is important later.

Now let’s create custom service behavior that will allow us to use our IocInstanceProvider:

    public class IoCServiceBehavior : Attribute, IServiceBehavior
    {
        public IoCServiceBehavior()
        {
            builder = new ContainerBuilder();
            builder.RegisterType<ConstCalculator>().As<ICalculator>();
        }

        #region IServiceBehavior Members

        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
            Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (var channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                var channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                if (channelDispatcher != null)
                {
                    foreach (var endpointDispatcher in channelDispatcher.Endpoints)
                    {
                        endpointDispatcher.DispatchRuntime.InstanceProvider =
                            new IocInstanceProvider(serviceDescription.ServiceType, builder.Build());
                    }
                }
            }
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }

        #endregion

        private readonly ContainerBuilder builder;
    }

Inside constructor of IoCServiceBehavior we do create autofac containerBuilder and register needed types. As you know we can apply our behavior to any service by subclassing from Attribute. That is why it is really important not to register our actual services inside container builder and that is why ResolveUnregistered() method was previously introduced. I’m really missing Unity and it’s kindness of resolving of unregistered types. Anyways… lets mark our service with IoCServiceBehavior attribute:

    [IoCServiceBehavior]
    public class Service1 : IService1
    {
        public Service1(ICalculator calculator)
        {
            this.calculator = calculator;
        }

        #region IService1 Members

        public int Foo()
        {
            return calculator.Calculate();
        }

        #endregion

        private ICalculator calculator;
    }

And we’re done:

Resolving service instance using autofac

Service instance is resolved and dependency is shown

Service result is 5. Bingo!

You can download sources here (zip archive, 8.88 Kb)

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: