My favorites | Sign in
Logo
                
Search
for
Updated Aug 13, 2008 by nicholas.blumhardt
WcfIntegration  
Autofac can host services in a WCF server, and can increase the reliability of WCF clients.

Getting Started

Autofac.Integration.Wcf.dll is included in the Autofac binary downloads. To use the integration you need to reference it as well as Autofac.dll in your project.

Clients

The proxy objects returned from ChannelFactory.CreateChannel<T>() need to be disposed before client and server resources assigned to the channel are freed. This is where Autofac's deterministic disposal really shines.

To take advantage of this, register and use your channel factories through a container client-side.

Registration

Something like the following needs to run during application startup:

var builder = new ContainerBuilder();

builder.Register(c => new ChannelFactory<ITrackListing>(
  new BasicHttpBinding(),
  new EndpointAddress("http://localhost/TrackListingService")));

builder.Register(c => c.Resolve<ChannelFactory<ITrackListing>>().CreateChannel())
  .FactoryScoped();

// Another application class not using WCF
builder.Register<AlbumPrinter>()
  .FactoryScoped();

var container = builder.Build();

The Register() method infers the ITrackListing service type from the return value of the expression, which is the result of channelFactory.CreateChannel(). The call to CreateChannel() isn't executed until ITrackListing is requested from the container.

Using the Service

Our application prints a track listing to the console using the remote ITrackListing service. It does this via the AlbumPrinter class:

class AlbumPrinter
{
  readonly ITrackListing _trackListing;

  public AlbumPrinter(ITrackListing trackListing)
  {
    _trackListing = trackListing;
  }

  public void PrintTracks(string artist, string album)
  {
    foreach (var track in _trackListing.GetTracks(artist, album))
      Console.WriteLine("{0} - {1}", track.Position, track.Title);
  }
}

If you haven't read up on nested containers, you might want to check out the documentation now.

using(var inner = container.CreateInnerContainer())
{
  var albumPrinter = inner.Resolve<AlbumPrinter>();
  albumPrinter.PrintTracks("The Shins", "Wincing the Night Away");
}

The important thing to note in this small example is that neither the client code of the album printer, nor the album printer itself, has to be aware that the ITrackListing service is in fact a WCF service and needs to be disposed. The container takes care of this housekeeping automatically when inner is disposed by the using block.

Servers Hosted in IIS

To use the integration from an IIS-hosted application, reference both Autofac.dll and Autofac.Integration.Wcf.dll.

In your global application startup, build a Container and set AutofacServiceHostFactory.Container:

var builder = new ContainerBuilder();
builder.Register<TestService.Service1>().FactoryScoped();
AutofacServiceHostFactory.Container = builder.Build();

Then, for each service create a .svc file with the Factory attribute set:

<%@ ServiceHost
    Service="TestService.Service1, TestService"
    Factory="Autofac.Integration.Wcf.AutofacWebServiceHostFactory, Autofac.Integration.Wcf" %>

You do not need to register your service type's contracts in Autofac - WCF will get this information from your configuration file.

An example is included in the /trunk/examples folder.

Resources

See the original discussion thread.


Comment by rodgarcialima, Oct 06, 2008

Hi Nicholas, I have a problem with the binding configuration. This config above has no effect, do you know why?

            // AssinadorService
            builder.Register(c => new ChannelFactory<IAssinadorService>(
                new BasicHttpBinding()
                {
                    CloseTimeout = new TimeSpan(0, 5, 0),
                    OpenTimeout = new TimeSpan(0, 5, 0),
                    ReceiveTimeout = new TimeSpan(0, 10, 0),
                    SendTimeout = new TimeSpan(0, 10, 0),
                    AllowCookies = false,
                    BypassProxyOnLocal = true,
                    HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
                    MaxBufferSize = int.MaxValue,
                    MaxBufferPoolSize = int.MaxValue,
                    MaxReceivedMessageSize = int.MaxValue,
                    MessageEncoding = WSMessageEncoding.Text,
                    TextEncoding = System.Text.Encoding.UTF8,
                    TransferMode = TransferMode.Buffered,
                    UseDefaultWebProxy = true
                },
                new EndpointAddress(ConfigurationManager.AppSettings["AssinadorServiceUrl"])));
            builder.Register(c => c.Resolve<ChannelFactory<IAssinadorService>>().CreateChannel() ).FactoryScoped();
            builder.Register<NfeUtilV1>().OnActivating(ActivatingHandler.InjectProperties).WithScope(Autofac.InstanceScope.Factory);

            Autofac.Integration.Wcf.AutofacServiceHostFactory.Container = builder.Build();

Thanks,

Rodrigo Lima

Comment by rodgarcialima, Oct 06, 2008

I Find a solution:

// AssinadorService
            builder.Register(c => new ChannelFactory<IAssinadorService>("basic")); // endpointConfigurationName
            builder.Register(c => c.Resolve<ChannelFactory<IAssinadorService>>().CreateChannel() ).FactoryScoped();
            builder.Register<NfeUtilV1>().OnActivating(ActivatingHandler.InjectProperties).WithScope(Autofac.InstanceScope.Factory);

            Autofac.Integration.Wcf.AutofacServiceHostFactory.Container = builder.Build();
Comment by marko.podgorsek, Oct 24, 2008

I would be very interested in something like System.ServiceModel?.Activation.WebScriptServiceHostFactory?, which automatically adds ASP.NET AJAX endpoint to a service (it serializes to JSON, not to SOAP), but is implemented with AutoFac? and supports property injection (like the one in Pages) and some transaction management (so I could add an attribute Transactional? to the method.

Comment by matt.wissman, Mar 24, 2009

I would like to point out that

<%@ ServiceHost
    Service="TestService.Service1, TestService"
    Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>

is for basicHttpBinding and wsHttpbinding (SOAP web services).

<%@ ServiceHost
    Service="TestService.Service1, TestService"
    Factory="Autofac.Integration.Wcf.AutofacWebServiceHostFactory, Autofac.Integration.Wcf" %>

Works for webHttpBinding (RESTful web services).


Sign in to add a comment
Hosted by Google Code