Using Autofac with AJAX-enabled WCF Service

2019-05-30 19:10发布

I am desperately trying to get this to work. I have used WCF services to do AJAX with JQuery before without any hustle.

Now I am using Autofac for DI, and so far it is going quiet good, until I want a WCF service in my UI project to be the base for AJAX. In my regular Webapplication I am using Global.asax 'Application_Start' to register my containers. This is done by calling a Boot() method in my 'MyBootstrapper' project. The Boot() method simply registers all my modules.

Now I noticed that having a WCF Service and by using the 'AJAX-enabled WCF Service' template, the Global.asax is not called once the service is invoked.

For this I have made a simple MyServiceHostFactory with a void host_Opening method that calls my Boot() method in my Bootstrapper. This seems to go well. Although nothing is set up.

Here is my WCF code:

    [ServiceContract(Namespace = "MyWebApp.UI.Ajax")]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class MyAsyncService
    {
        public IPersonProvider PersonManager { get; set; }

        [OperationContract]
        [WebGet(ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
        public List<Person> GetPersons()
        {
            var persons = PersonManager.GetPersons();
            return persons;
        }
    }

Markup of MyAsyncService

<%@ ServiceHost Language="C#" Debug="true" Service="MyWebApp.UI.Ajax.MyAsyncService" CodeBehind="MyAsyncService.svc.cs" Factory="MyWebApp.UI.Ajax.MyAsyncServiceHostFactory"%>

MyAsyncServiceHostFactory:

public class MyAsyncServiceHostFactory : ServiceHostFactory, IContainerProviderAccessor
    {
        static IContainerProvider _containerProvider;

        public IContainerProvider ContainerProvider
        {
            get { return _containerProvider; }
        }

        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            var host = base.CreateServiceHost(serviceType, baseAddresses);
            host.Opening += host_Opening;
            return host;
        }

        void host_Opening(object sender, EventArgs e)
        {
            // Setup Autofac stuff.
            var container = MyBootLoader.Boot();
            _containerProvider = new ContainerProvider(container);
        }
    }

And MyBootLoader:

 public static class MyBootLoader
    {
        public static IContainer Boot()
        {
            var builder = ConfigureContainer();
            return builder.Build();
        }

        private static ContainerBuilder ConfigureContainer()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<PersonManager>().As<IPersonProvider>().InstancePerHttpRequest();
            return builder;
        }
    }

My web.config:

  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="MyWebApp.UI.Ajax.MyAsyncServiceAspNetAjaxBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <services>
      <service name="MyWebApp.UI.Ajax.MyAsyncService">
        <endpoint address="" behaviorConfiguration="MyWebApp.UI.Ajax.MyAsyncServiceAspNetAjaxBehavior"
          binding="webHttpBinding" contract="MyWebApp.UI.Ajax.MyAsyncService" />
      </service>
    </services>
  </system.serviceModel>

What am I missing, please? Everything seems to get through, but my PersonManager is NULL in MyAsyncService.

2条回答
ら.Afraid
2楼-- · 2019-05-30 19:23

Have you followed the instruction on the wiki for IIS hosting services?

https://code.google.com/p/autofac/wiki/WcfIntegration#IIS_Hosted_Services

You normally configure your container in Application_Start and set the AutofacHostFactory.Container property with the newly built container. Then set the factory in your .svc file to AutofacWebServiceHostFactory. If you need to customise the factory for some reason you should derive from one of the existing Autofac factory implementations. These add the behavior to the endpoint that is responsible for the dependency injection.

查看更多
冷血范
3楼-- · 2019-05-30 19:28

I got my friend helping me, and the solution was to keep my *.svc file in my web.ui project and the codebehind file in another UI.Services project.

In the markup file of my *.svc file the following was added:

<%@ ServiceHost Language="C#" Debug="true" Service="MyWebApp.UI.Services.MyAsyncService, MyWebApp.UI.Services"  Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>

This prevented the circular reference problem, but with the cost of an addition of a new assembly.

In my bootloader I added the following:

public static class MyBootLoader
{
    public static IContainer Boot()
    {
        var builder = ConfigureContainer();
        var container = builder.Build();

        AutofacHostFactory.Container = container;

        return container;
    }
    private static ContainerBuilder ConfigureContainer()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<PersonManager>().As<IPersonProvider>().InstancePerHttpRequest();
        return builder;
    }
}
查看更多
登录 后发表回答