Reputation: 88
I've been scouring the web for a solution for an issue I have. I'm unable to wire up my WCF services (IIS hosted) for interception - I'm able to do so for all the other classes / interfaces I've specified.
My code is as follows:
ReportingService.svc
<%@ ServiceHost Language="C#" Debug="true" Service="myNameSpace.ReportingService, myNameSpace" Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
ReportingService.cs
namespace myNameSpace
{
public class ReportingService : IReportingService
{
public ReportingService()
{
}
public virtual ReportResponse GetReport(ReportRequest request)
{
//Arbitrary code
}
}
}
Container Initialization
[assembly: WebActivator.PreApplicationStartMethod(typeof(myNameSpace.App_Start.AutofacInitialization), "Start")]
namespace myNameSpace.App_Start
{
//using's removed to save space
public static class AutofacInitialization
{
public static void Start()
{
var builder = new ContainerBuilder();
builder.Register(x => new AuditInterceptor());
//Working - Context registered and interception working as expected
builder.RegisterType<ReportContext>().As<IReportContext>.EnableClassInterceptors().InterceptedBy(typeof(AuditInterceptor));
//Fails - The following causes a runtime exception of "The client and service bindings may be mismatched."
builder.RegisterType<ReportingService>().EnableClassInterceptors().InterceptedBy(typeof(AuditInterceptor));
AutofacServiceHostFactory.Container = builder.Build();
}
}
}
As indicated above, when enabling interception on the ReportingService, I get a runtime exception. If I remove the interception and just use
builder.RegisterType<ReportingService>()
the service runs fine but obviously no interception.
I have had a look at the wiki but am having no joy.
Any ideas as to what I'm doing wrong?
Upvotes: 0
Views: 1251
Reputation: 23924
There is some "magic" inside WCF where if you tell the service host the name of the concrete type you're hosting, it expects you to always only host just that concrete type.
Using class interceptors, Castle.DynamicProxy2 is generating a new type with the same signature and everything of the concrete, but when you try to resolve the concrete type you'll get the dynamic proxy type instead.
Since that's not literally the same as the original concrete type, WCF explodes. I ran into this when working with the Autofac support for multitenant service hosting.
The solution is to tell Autofac the interface type to host rather than the concrete type. (This is "Contract Type Registration" on the Autofac WCF integration wiki page.) Then register things using interface interceptors and using the interface as the exposed service.
In your .svc file, then, it'd be:
<%@ ServiceHost
Language="C#"
Debug="true"
Service="myNameSpace.IReportingService, myNameSpace"
Factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" %>
The registration for the service type would look like:
builder.RegisterType<ReportingService>()
.As<IReportingService>()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(AuditInterceptor));
Now when WCF gets the concrete type to host, it'll get the dynamic proxy type instead of the base/intercepted concrete type and you shouldn't get the runtime binding error.
Upvotes: 1