ServiceActivationException when auto-starting WCF services with AutofacServiceHostFactory
ServiceActivationException when auto-starting WCF services with AutofacServiceHostFactory
I switched teams at work and as a welcome gift into the new team I got to investigate the following error:
Exception: System.ServiceModel.ServiceActivationException: The service '/AuthorisationService.svc' cannot be activated due to an exception during compilation. The exception message is: The AutofacServiceHost.Container static property must be set before services can be instantiated.. —> System.InvalidOperationException: The AutofacServiceHost.Container static property must be set before services can be instantiated. at Autofac.Integration.Wcf.AutofacHostFactory.CreateServiceHost(String constructorString, Uri[] baseAddresses) at System.ServiceModel.ServiceHostingEnvironment.HostingManager.CreateService(String normalizedVirtualPath, EventTraceActivity eventTraceActivity) at System.ServiceModel.ServiceHostingEnvironment.HostingManager.ActivateService(ServiceActivationInfo serviceActivationInfo, EventTraceActivity eventTraceActivity) at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath, EventTraceActivity eventTraceActivity) — End of inner exception stack trace — at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath, EventTraceActivity eventTraceActivity) at System.ServiceModel.ServiceHostingEnvironment.EnsureServiceAvailableFast(String relativeVirtualPath, EventTraceActivity eventTraceActivity) Process Name: w3wp Process ID: 9776
The troublesome service is hosted in an ASP.NET
web application and it's preloaded with a custom implementation of IProcessHostPreloadClient
which more or less does what's described in this blog post. Since the project hosting the service is using AutoFac as it's DI framework/library the service is setup to use AutofacServiceHostFactory
as the service factory:
<%@ ServiceHost Service="AuthorizationServiceImpl, AuthorizationService" Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
After some googling for the error I turned out to the AutoFac documentation page where I got the first idea of what is happening:
When hosting WCF Services in WAS (Windows Activation Service), you are not given an opportunity to build your container in the ApplicationStart event defined in your Global.asax because WAS doesn’t use the standard ASP.NET pipeline.
Ok, great! Now I know that ServiceHostingEnvironment.EnsureServiceAvailable()
method (which is called to activate the service) doesn't use the HTTP pipeline from ASP.NET. A solution to this issue is in the next paragraph of the documentation:
The alternative approach is to place a code file in your
App_Code
folder that contains a type with apublic static void AppInitialize()
method.
And that's what I did. I went to to the project in Visual Studio, added a special ASP.NET folder
named App_Code
and added a class named AppStart
to it with a single method public static void AppInitialize()
which contained all the required bootstrapping logic for AutoFac. I redeployed the application on but the error kept popping and it's after carefully reading the comments from this StackOverflow answer and this blog post on how to initialize WCF services I found why the AppInitialize
method wasn't invoked: it was because the AppStart.cs
needs it's build action to be Content
not Compile
So when getting the ServiceActivationexception
with the error message The AutofacServiceHost.Container static property must be set before services can be instantiated
make sure to have the following:
- The special ASP.NET folder
App_Code
- A class in
App_Code
having a method with this signaturepublic static void AppInitialize()
which contains all the required initialization code - The build action of the file containing the above method is set to
Content
as shown in the picture below
How to Initialize Hosted WCF Services
Using AppInitialize
The above global.asax does not work for non-HTTP protocols such as net.tcp and net.pipe that is supported by the Windows Activation Service (WAS) on Windows Vista. There is no protocol-agnostic counterpart for HttpApplication in this case.
Fortunately, ASP.NET provides a simple hook that works in a protocol agnostic way. The hook is based on the following AppInitialize method:
public static void AppInitialize();
This method can be put in any type that is defined in a C# file in the application’s \App_Code directory. When the AppDomain is started, ASP.NET checks whether there is a type that has such as method (exact name and signature) and invokes it. Note that the AppInitialize method can be only defined once and it has to be in a code file instead of a pre-compiled assembly.