|
WcfIntegration
Autofac can host services in a WCF server, and can increase the reliability of WCF clients.
Getting StartedAutofac.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. ClientsThe 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. RegistrationSomething 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 ServiceOur 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 IISTo 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. ResourcesSee the original discussion thread. |
Sign in to add a comment
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
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();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.
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).