WCF Integration Guide¶
The Simple Injector WCF Integration NuGet Package allows WCF services to be resolved by the container, which enables constructor injection.
After installing this NuGet package, it must be initialized in the start-up path of the application by calling the SimpleInjectorServiceHostFactory.SetContainer method:
protected void Application_Start(object sender, EventArgs e)
{
// Create the container as usual.
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
// Register WCF services.
container.RegisterWcfServices(Assembly.GetExecutingAssembly());
// Register your types, for instance:
container.Register<IUserRepository, SqlUserRepository>();
container.Register<IUnitOfWork, EfUnitOfWork>(Lifestyle.Scoped);
// Register the container to the SimpleInjectorServiceHostFactory.
SimpleInjectorServiceHostFactory.SetContainer(container);
}
For each service class, you should supply a factory attribute in the .SVC file of each service class. For instance:
<%@ ServiceHost
Service="UserService"
CodeBehind="UserService.svc.cs"
Factory="SimpleInjector.Integration.Wcf.SimpleInjectorServiceHostFactory,
SimpleInjector.Integration.Wcf"
%>
WAS Hosting and Non-HTTP Activation¶
When hosting WCF Services in WAS (Windows Activation Service), you are not given an opportunity to build your container in the Application_Start event defined in your Global.asax because WAS doesn’t use the standard ASP.NET pipeline. A workaround for this is to move the container initialization to a static constructor:
public static class Bootstrapper
{
public static readonly Container Container;
static Bootstrapper()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
// Register WCF services.
container.RegisterWcfServices(Assembly.GetExecutingAssembly());
// register all your components with the container here:
// container.Register<IService1, Service1>()
// container.Register<IDataContext, DataContext>(Lifestyle.Scoped);
container.Verify();
Container = container;
}
}
Your custom ServiceHostFactory can now use the static Bootstrapper.Container field:
public class WcfServiceFactory : SimpleInjectorServiceHostFactory
{
protected override ServiceHost CreateServiceHost(
Type serviceType, Uri[] baseAddresses)
{
return new SimpleInjectorServiceHost(
Bootstrapper.Container,
serviceType,
baseAddresses);
}
}
Optionally, you can apply your custom service behaviors and contract behaviors to the service host:
public class WcfServiceFactory : SimpleInjectorServiceHostFactory
{
protected override ServiceHost CreateServiceHost(
Type serviceType, Uri[] baseAddresses)
{
var host = new SimpleInjectorServiceHost(
Bootstrapper.Container,
serviceType,
baseAddresses);
// This is all optional
this.ApplyServiceBehaviors(host);
this.ApplyContractBehaviors(host);
return host;
}
private void ApplyServiceBehaviors(ServiceHost host)
{
foreach (var behavior in this.container.GetAllInstances<IServiceBehavior>()) {
host.Description.Behaviors.Add(behavior);
}
}
private void ApplyContractBehaviors(SimpleInjectorServiceHost host)
{
foreach (var behavior in this.container.GetAllInstances<IContractBehavior>())
{
foreach (var contract in host.GetImplementedContracts())
{
contract.Behaviors.Add(behavior);
}
}
}
}
For each service class, you should supply a factory attribute in the .SVC file of each service class. Assuming the customly defined factory is defined in the MyComp.MyWcfService.Common namespace of the MyComp.MyWcfService assembly, the markup would be the following:
<%@ ServiceHost
Service="UserService"
CodeBehind="UserService.svc.cs"
Factory="MyComp.MyWcfService.Common.WcfServiceFactory, MyComp.MyWcfService"
%>