简体   繁体   中英

Autofac WCF registration exception with svc-less service

I'm trying to set up Autofac as my DI container for a new WCF project I am working on. We're working with a svc-less configuration and self hosting. Without Autofac and simply using poor-man's DI, everything is working exactly as desired, but when I add Autofac into the mix, something is going awry.

The code I am using to set everything up is:

  public class CustomServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        var container = InitializeDIContainer();
        var customHost = new CustomServiceHost(serviceType, baseAddresses);
        // Exception is being thrown on the line below
        customHost.AddDependencyInjectionBehavior(serviceType, container);
        return customHost;
    }

    private static IContainer InitializeDIContainer()
    {
        var builder = new ContainerBuilder();
        builder.RegisterAssemblyTypes(typeof (AccountRepository).Assembly)
            .Where(t => t.Name.EndsWith("Repository"))
            .As(t => t.GetInterfaces().FirstOrDefault(
                i => i.Name == "I" + t.Name));

        builder.RegisterAssemblyTypes(typeof (AccountService).Assembly)
            .Where(t => t.Name.EndsWith("Service"))
            .As(t => t.GetInterfaces().FirstOrDefault(
                i => i.Name == "I" + t.Name));

        builder.RegisterType<tktktktkDbContext>().As<IDataContextAsync>();
        builder.RegisterType<UnitOfWork>().As<IUnitOfWorkAsync>();

        var container = builder.Build();
        return container;
    }
}

When this runs, I am getting the following exception:

An exception of type 'System.ArgumentException' occurred in Autofac.Integration.Wcf.dll but was not handled in user code.
Additional information: The service contract type 'tktktktk.Services.AccountClassService' has not been registered in the container.

When I put a breakpoint in the code and inspect the container, I can see all of my services, including the 'tktktktk.Services.AccountClassService' object, in the ComponentRegistry.Registrations collection.

I've tried reworking my web.config file to use the "Autofac.Integration.Wcf.AutofacServiceHostFactory" factory, but then my application fails before it even gets to this point.

I'm thinking that I missed a step somewhere, but am at a loss for what. Any assistance would be greatly appreciated!

UPDATE

I modified my web.config to use "Autofac.Integration.Wcf.AutofacServiceHostFactory" as indicated. I am now getting the following error:

WebHost failed to process a request.
 Sender Information: System.ServiceModel.ServiceHostingEnvironment+HostingManager/45653674
 Exception: System.ServiceModel.ServiceActivationException: The service '/Account/AccountClassService.svc' cannot be activated due to an exception during compilation.  The exception message is: The AutofacServiceHost.Container static property must be set before services can be instantiated.. ---> System.InvalidOperationException: The AutofacServiceHost.Container static property must be set before services can be instantiated.

UPDATE 2

I tried what is suggested in the answer below, and I got the same error as above. One thing I noted, When I added AutofacServiceHost.Container = container to my code, that would not compile. I switched that to AutofacHostFactory.Container and it compiled fine. Also, with the web.config changed to use Autofac.Integration.Wcf.AutofacServiceHostFactory , I no longer hit any breakpoints in this code, suggesting that it is being bypassed completely now.

I also attempted svc-less configuration. I followed the steps in the documentation and received this error message:

The service 'MyService' configured for WCF is not registered with the Autofac container. 

It turns out everything was registered correctly however the "add factory" element in web.config needs the assembly name of the service just as the .svc file would if it existed:

<add factory="Autofac.Integration.Wcf.AutofacServiceHostFactory" relativeAddress="~/MyService.svc" service="NameSpace.Service, AssemblyName" />

The Autofac documentation does not mention this or show it in the example. Also, Visual Studio will complain and underline the attribute however the service will run correctly.

Here's the situation you're using your custom host, on the other hand the Autofac have it's builtin ServiceHost provided as out of the box feature.

You need to set the property Container of AutofacServiceHost class:

 public class CustomServiceHostFactory : ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            var container = InitializeDIContainer();

            // Add this line and try again.
            AutofacServiceHost.Container = container;

            var customHost = new CustomServiceHost(serviceType, baseAddresses);

            customHost.AddDependencyInjectionBehavior(serviceType, container);
            return customHost;
        }

        private static IContainer InitializeDIContainer()
        {
            var builder = new ContainerBuilder();
            builder.RegisterAssemblyTypes(typeof (AccountRepository).Assembly)
                .Where(t => t.Name.EndsWith("Repository"))
                .As(t => t.GetInterfaces().FirstOrDefault(
                    i => i.Name == "I" + t.Name));

            builder.RegisterAssemblyTypes(typeof (AccountService).Assembly)
                .Where(t => t.Name.EndsWith("Service"))
                .As(t => t.GetInterfaces().FirstOrDefault(
                    i => i.Name == "I" + t.Name));

            builder.RegisterType<tktktktkDbContext>().As<IDataContextAsync>();
            builder.RegisterType<UnitOfWork>().As<IUnitOfWorkAsync>();

            var container = builder.Build();
            return container;
        }
    }

I ran into this problem myself. I managed to solve this by using the Named style registration

```

 builder.RegisterType<YourServiceType>()
            .Named<object>("myservice");

 //and in your config:..

<serviceHostingEnvironment multipleSiteBindingsEnabled="true" >
  <serviceActivations>
    <add relativeAddress="~/serviceurl.svc" service="myservice" factory="Autofac.Integration.Wcf.AutofacServiceHostFactory"/>
  </serviceActivations>
</serviceHostingEnvironment>

```

Note that in my case i am not using apsnetcompatibilitymode.

I think its a bug in the AutofacHostFactory, its using the wrong servicename identifier to resolve the wcfservice type. Using the Named registration style, your basically making sure that the type the registration is known under and the name used by the AutofacHostFactory match up

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM