简体   繁体   中英

How do I host a rest service with autofac and wcf?

Following this guide I managed to get a service working over iis with was. https://code.google.com/p/autofac/wiki/WcfIntegration#Self-Hosted_Services

However, I also need it host a rest service. I could actually live with only rest.

But with the documentation available I have not been successful yet.

Does anyone have a good guide for getting it working with rest service with wcf(was)+autofac?

I do not seem to get the endpoint right, no endpoint at all actually.

My code, where did I miss something?

namespace WcfServiceHost.Infrastructure
{
    public class AutofacContainerBuilder
    {

        public static IContainer BuildContainer()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<LoginFactory>().As<ILoginFactory>();
            builder.RegisterType<SupplierHandler>().As<ISupplierHandler>();
            builder.RegisterType<UserHandler>().As<IUserHandler>();
            builder.RegisterType<SupplierRepository>().As<ISupplierRepository>();
            builder.RegisterType<TidsamProductSupplierProxy>().As<ILogin>();

            builder.RegisterType<StoreService>().As<IStoreService>();
            //builder.RegisterType<StoreService>();

            return builder.Build();
        }
    }
}



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



namespace WcfServiceHost.App_Code
// ReSharper restore CheckNamespace
{
    public static class AppStart
    {
        public static void AppInitialize()
        {
            // Put your container initialization here.
            // build and set container in application start
            IContainer container = AutofacContainerBuilder.BuildContainer();
            AutofacHostFactory.Container = container;

            // AutofacWebServiceHostFactory  AutofacServiceHostFactory
            RouteTable.Routes.Add(new ServiceRoute("StoreService", new RestServiceHostFactory<IStoreService>(), typeof(StoreService)));

        }
    }
}



 public class RestServiceHostFactory<TServiceContract> : AutofacWebServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            ServiceHost host = base.CreateServiceHost(serviceType, baseAddresses);
            var webBehavior = new WebHttpBehavior
            {
                AutomaticFormatSelectionEnabled = true,
                HelpEnabled = true,
                FaultExceptionEnabled = true
            };
            var endpoint = host.AddServiceEndpoint(typeof(TServiceContract), new WebHttpBinding(), "Rest");
            endpoint.Behaviors.Add(new WebHttpBehavior { HelpEnabled = true });
            endpoint.Name = "rest";
            endpoint.Behaviors.Add(webBehavior);

            return host;
        }

    }

config:

<system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
      <serviceActivations>
        <add factory="Autofac.Integration.Wcf.AutofacServiceHostFactory"
         relativeAddress="~/StoreService.svc"
         service="Services.StoreService" />
      </serviceActivations>
    </serviceHostingEnvironment>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </modules>
    <handlers>
      <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" />
    </handlers>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

Then I do get an endpoint. But as soon as I change to AutofacWebServiceHostFactory I get no endpoint and no rest/help. However, I can query the rest services in IStoreService.

A registration of REST WCF service is almost similar to registration non-REST WCF service. Only changed a few things: bindings, endpoints and service contract.

Modified example from the autofac wiki with WCF REST service (very simplified).

The interface and implementation for the logger that will be the dependency.

public interface ILogger
{
    void Write(string message);
}

public class Logger : ILogger
{
    public void Write(string message)
    {
        Console.WriteLine(message);
    }
}

The contract and implementation for the rest wcf service.

[ServiceContract]
public interface IEchoService
{
    [OperationContract]
    [WebGet(UriTemplate = "/Echo/{message}")]
    string RestEcho(string message);
}

public class EchoService : IEchoService
{
    private readonly ILogger _logger;

    public EchoService(ILogger logger)
    {
        _logger = logger;
    }

    public string RestEcho(string message)
    {
        _logger.Write(message);
        return message;
    }
}

The Console Application code for building the container and hosting the web service.

class Program
{
    static void Main()
    {
        ContainerBuilder builder = new ContainerBuilder();
        builder.Register(c => new Logger()).As<ILogger>();
        builder.Register(c => new EchoService(c.Resolve<ILogger>())).As<IEchoService>();

        using (IContainer container = builder.Build())
        {
            Uri address = new Uri("http://localhost:8080/EchoService");
            ServiceHost host = new ServiceHost(typeof(EchoService), address);

            var binding = new WebHttpBinding();
            var endpointAddress = new EndpointAddress(address);
            var description = ContractDescription.GetContract(typeof(IEchoService));
            var endpoint = new ServiceEndpoint(description, binding, endpointAddress);
            endpoint.Behaviors.Add(new WebHttpBehavior { HelpEnabled = true });
            host.AddServiceEndpoint(endpoint);

            host.AddDependencyInjectionBehavior<IEchoService>(container);

            host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true, HttpGetUrl = address });
            host.Open();

            Console.WriteLine("The host has been opened.");
            Console.ReadLine();

            host.Close();
            Environment.Exit(0);
        }
    }
}

For testing, run any browser and open a url http://localhost:8080/EchoService/Echo/test_test

To solve this. I removed the reference to the autofac AutofacServiceHostFactory in the config. Then I wrote endpoints manually with behaviors.

I used AutofacServiceHostFactory in the .svc file for the service.

This was not the way I'd prefer to do it but otherwise I didn't both the rest endpoint and the basichttp soap endpoint to work.

If someone has a better solution, I'll give you the answer.


@John Meyer Upon request for my code sample, I managed to find some old code.

The service like EmailService.svc in my folder Services, edit like so:

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

in web.config

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  <dependentAssembly>
    <assemblyIdentity name="Autofac" publicKeyToken="x" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.5.0.0" newVersion="3.5.0.0" />
  </dependentAssembly>
  <dependentAssembly>

AppStart class

public static class AppStart
{
    public static void AppInitialize()
    {
        IContainer container = AutofacContainerBuilder.BuildContainer();
        AutofacHostFactory.Container = container;}
}
...

I seperated the container to another class. Dont forget the correct using using Autofac;

and the method in the class to set up the container

public static IContainer BuildContainer()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<EmailService>().As<IEmailService>();
            return builder.Build();
        }

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