Using Autofac for DI into WCF service hosted in ASP.NET application

Viewed 10744

I'm having trouble injecting services dependencies into my WCF service using Autofac 1.4.5. I've read and followed the Autofac wiki page on WcfIntegration but my debugging shows me that my WCF service is created by the System.ServiceModel.Dispatcher.InstanceBehavior.GetInstance() method and not by the AutofacWebServiceHostFactory. What am I doing wrong?

I've set up my ajax.svc file to look like the one in the example for use with WebHttpBinding:

<%@ ServiceHost Language="C#" Debug="true"
    Service="Generic.Frontend.Web.Ajax, Generic.Frontend.Web"
    Factory="Autofac.Integration.Wcf.AutofacWebServiceHostFactory,
             Autofac.Integration.Wcf" %>

My WCF service class Ajax is defined like this:

namespace Generic.Frontend.Web
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(
        RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Ajax
    {
        public MapWebService MapWebService { get; set;}

        public Ajax() {
            // this constructor is being called
        }

        public Ajax(MapWebService mapWebService)
        {
            // this constructor should be called
            MapWebService = mapWebService;
        }

        [WebGet(ResponseFormat = WebMessageFormat.Json)]
        [OperationContract(Name = "mapchange")]
        public MapChangeResult ProcessMapChange(string args)
        {
            // use the injected service here
            var result = MapWebService.ProcessMapChange(args);
            return result;
        }
    }
}

Now I've used the wiring up in the Global.asax.cs as shown in the wiki mentioned above:

var builder = new ContainerBuilder();
builder.RegisterModule(new AutofacModuleWebservice());
var container = builder.Build();
AutofacServiceHostFactory.Container = container;

with

class AutofacModuleWebservice : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.Register<Ajax>();
        builder.Register<MapWebService>().ContainerScoped();
    }
}

In my web.config I have

<services>
    <service name="Generic.Frontend.Web.Ajax">
        <endpoint address="http://mysite.com/ajax.svc/" binding="webHttpBinding"
                  contract="Generic.Frontend.Web.Ajax" />
    </service>
</services>

.

The service already works fine but I can't get the Autofac bits (read: creation/injection) to work. Any ideas?

Edit: Removing the default constructor unfortunately leads to the following exception:

System.InvalidOperationException:
The service type provided could not be loaded as a service because it does not
have a default (parameter-less) constructor. To fix the problem, add a default
constructor to the type, or pass an instance of the type to the host.

Cheers, Oliver

5 Answers

I just got the same System.InvalidOperationException and solved it by changing the ServiceBehavior InstanceContextMode of the implementation from InstanceContextMode.PerCall to InstanceContextMode.PerSession, perhaps your AutoFac lifetime scope is out of sync with your web service implementation?

For testing AutoFac service creation I recommend creating a unit test and directly resolving them as this will highlight any issues and give more meaningful exception messages. For services with a request lifetime scope create a test aspx page and again resolve them directly.

Related