Making HttpContext.Current Available Within a WCF Service
Posted by Dylan Beattie on 24 February 2011 • permalinkI needed to add a quick’n’dirty WCF service to an ASP.NET MVC web application, so I could call a handful of methods from a different application.
The MVC app in question is using Windsor, NHibernate and the repository pattern, so we’ve got a fairly standard pattern where we spin up a ManagedWebSessionContext in the Application_BeginRequest handler (in global.asax.cs) and then flush and close the session in Application_EndRequest(). I used the Windsor WCF facility to inject a bunch of dependencies into a little WCF service, but I was finding that SessionFactory.GetCurrentSession() was always returning null – because when you’re using the ManagedWebSessionContext, your NHibernate session is bound to your HttpContext.Current, and by default you don’t have one of these inside a WCF service.
However - if you can live with tight coupling between your WCF service and IIS hosting, there’s a couple of little config things you’ll need to do to get this working. What doesn’t help is that until you’ve got all this just right, you’ll get a really helpful “Failed to Execute URL” error from IIS that’ll tell you absolutely nothing about what’s wrong.
First, make sure WCF HTTP activation is installed on your server – in Windows 2008, it’s under Server Manager –> Features:
Next, make sure you’ve registered the WCF service model with IIS, by running:
C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\> ServiceModelReg.exe –i
Next, make sure your web service is running in ASP.NET compatibility mode. First, check you’ve got this:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
in your web.config file, and then decorate your service implementation with the AspNetCompatibilityRequirements attribute:
[AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Required)]
public class WcfMagicService : IMagicService {
. . .
}
The last thing I had to do was necessitated by WCF not supporting multiple host headers; I had to hard-wire the WCF endpoint to listen on a specific hostname. In this case, this involved tweaking the serviceHostingEnvironment section of web.config, which now looks like this:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<baseAddressPrefixFilters>
<add prefix=http://services.mydomain.com” />
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
And then adding another attribute to the service implementation class:
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
[AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Required)]
public class WcfMagicService : IMagicService {
}
Once that’s done, you’ll have an instantiated HttpContext.Current inside your service methods, so your code – and useful things like NHibernate’s ManagedWebSessionContext – will behave just as they do in normal MVC controllers or WebForms code-behind.