======================================
Windows Communication Foundation (WCF)
======================================
WCF integration for both clients and services requires the `Autofac.Wcf NuGet package `_.
WCF integration provides dependency injection integration for services as well as client proxies. **Due to WCF internals, there is no explicit support in WCF for per-request lifetime dependencies.**
.. contents::
:local:
Clients
=======
There are a couple of benefits to using Autofac in conjunction with your service client application:
- **Deterministic disposal**: Automatically free resources consumed by proxies created by ``ChannelFactory.CreateChannel()``.
- **Easy service proxy injection**: For types that consume services you can easily inject a dependency on the service interface type.
During application startup, for each service register a ``ChannelFactory`` and a function that uses the factory to open channels:
.. sourcecode:: csharp
var builder = new ContainerBuilder();
// Register the channel factory for the service. Make it
// SingleInstance since you don't need a new one each time.
builder
.Register(c => new ChannelFactory(
new BasicHttpBinding(),
new EndpointAddress("http://localhost/TrackListingService")))
.SingleInstance();
// Register the service interface using a lambda that creates
// a channel from the factory. Include the UseWcfSafeRelease()
// helper to handle proper disposal.
builder
.Register(c => c.Resolve>().CreateChannel())
.As()
.UseWcfSafeRelease();
// You can also register other dependencies.
builder.RegisterType();
var container = builder.Build();
In this example...
- The call to ``CreateChannel()`` isn't executed until ``ITrackListing`` is requested from the container.
- The ``UseWcfSafeRelease()`` configuration option ensures that exception messages are not lost when disposing client channels.
When consuming the service, add a constructor dependency as normal. This example shows an application that prints a track listing to the console using the remote ``ITrackListing`` service. It does this via the ``AlbumPrinter`` class:
.. sourcecode:: csharp
public 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);
}
}
When you resolve the ``AlbumPrinter`` class from a lifetime scope, the channel to the ``ITrackListing`` service will be injected for you.
Note that, given :doc:`the service proxy is disposable <../lifetime/disposal>`, it should be resolved from a child lifetime scope, not the root container. Thus, if you have to manually resolve it (for whatever reason), be sure you're creating a child scope from which to do it:
.. sourcecode:: csharp
using(var lifetime = container.BeginLifetimeScope())
{
var albumPrinter = lifetime.Resolve();
albumPrinter.PrintTracks("The Shins", "Wincing the Night Away");
}
Services
========
Quick Start
-----------
To get Autofac integrated with WCF on the service side you need to reference the WCF integration NuGet package, register your services, and set the dependency resolver. You also need to update your ``.svc`` files to reference the Autofac service host factory.
Here's a sample application startup block:
.. sourcecode:: csharp
protected void Application_Start()
{
var builder = new ContainerBuilder();
// Register your service implementations.
builder.RegisterType();
// Set the dependency resolver.
var container = builder.Build();
AutofacHostFactory.Container = container;
}
And here's a sample ``.svc`` file.
.. sourcecode:: aspx-cs
<%@ ServiceHost
Service="TestService.Service1, TestService"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
The sections below go into further detail about what each of these features do and how to use them.
Register Service Implementations
--------------------------------
You can register your service types in one of three ways: by type, by interface, or by name.
Register By Type
""""""""""""""""
Your first option is to simply register the service implementation type in the container and specify that implementation type in the .svc file. **This is the most common usage.**
In your application startup, you'd have code like this:
.. sourcecode:: csharp
var builder = new ContainerBuilder();
builder.RegisterType();
AutofacHostFactory.Container = builder.Build();
And your ``.svc`` file would specify the appropriate service implementation type and host factory, like this:
.. sourcecode:: aspx-cs
<%@ ServiceHost
Service="TestService.Service1, TestService"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
Note that **you need to use the fully-qualified name of your service in the .svc file**, i.e. ``Service="Namespace.ServiceType, AssemblyName"``.
Register by Interface
"""""""""""""""""""""
Your second option is to register the contract type in the container and specify the contract in the ``.svc`` file. This is handy if you don't want to change the ``.svc`` file but do want to change the implementation type that will handle requests.
In your application startup, you'd have code like this:
.. sourcecode:: csharp
var builder = new ContainerBuilder();
builder.RegisterType()
.As();
AutofacHostFactory.Container = builder.Build();
And your .svc file would specify the service contract type and host factory, like this:
.. sourcecode:: aspx-cs
<%@ ServiceHost
Service="TestService.IService1, TestService"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
Note that **you need to use the fully-qualified name of your contract in the .svc file**, i.e. ``Service="Namespace.IContractType, AssemblyName"``.
Register by Name
""""""""""""""""
The third option you have is to register a named service implementation in the container and specify that service name in the ``.svc`` file. This is handy if you want even further abstraction away from the ``.svc`` file.
In your application startup, you'd have code like this:
.. sourcecode:: csharp
var builder = new ContainerBuilder();
builder.RegisterType()
.Named