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?
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.
Related
We are defining implementations to our services in an external xml configuration file. We have the name of the service, the class to instantiate, the assembly containing the class. We are migrating from an Spring AOP code.
For simple services it works without an itch with kernel.Bind().To().
We load the assembly, create an instance, return it to To().
However some services inherit from another class like :
internal abstract Bar<T>: EntityBo<T> where T : IAddress
{
protected Bar(IAddress adr)
{
}
}
internal Foo:Bar<ILocalAddress>, ILocalAddressService {
}
When I try to get ILocalAddressService from the Kernel, I get a Ninject.ActivationException :
Error activating ILocalAddress No matching bindings are available, and
the type is not self-bindable.
Activation path:
2) Injection of dependency ILocalAddress into parameter adr of constructor of type Foo
1) Request for ILocalAddressService
The Kernel is in a different project and doesn't know about the interface or its implementation.
How can I make it work ?
I like the WCF 4.0 capabality to host a service without an .svc file by setting a serviceActivations in the config file. It work great using the default service factory but now I'm trying to do the same using the AutofaServiceHostFactory so my dependencies will be properly injected. In all scenarios I tried, I still got this error when I try to access to service : The service 'WCFAutofacWiring.MyService' configured for WCF is not registered with the Autofac container. I host my service in an empty asp.net web site. Here's what I did :
Web.config :
<serviceHostingEnvironment>
<serviceActivations>
<add factory="Autofac.Integration.Wcf.AutofacServiceHostFactory"
relativeAddress="~/WASCurrentTime.svc"
service="WCFAutofacWiring.MyService" />
</serviceActivations>
</serviceHostingEnvironment>
Then, I put a file in the app_code folder to register my dependency as stated in the Autofac documentation (Autofac WcfIntegration) and I confirmed with the debugger that the code is called at service start :
public static class AppStart
{
public static void AppInitialize()
{
AutofacHostFactory.Container = new AutofacBootstrapper().Configure();
}
}
Finally, here's my registrations :
public class AutofacBootstrapper
{
public IContainer Configure()
{
var builder = new ContainerBuilder();
// register types
builder.Register<ILanguageProvider>(x => new MyLanguageProvider("en-US"));
builder.RegisterType<MyService>();
return builder.Build();
}
}
My service works perfectly if a use an .svc file instead of serviceActivation but I find it wasteful to create an .svc file if the only reason is to setup a factory that I can specify in my web.config.
Any idea ?
Thanks
According to the Autofac source, the exception is thrown if either a keyed resolution with the given string (from config) or a typed resolution using Type.GetType for the given string fails.
In your case the Type.GetType method probably returns null because you haven't specified a Type.AssemblyQualifiedName in the config.
Try getting typeof(MyService).AssemblyQualifiedName and insert that into the config.
What is the correct method to wire-up your types in Ninject with WCF. I have got the WCF extensions and Ninject itself added to the WCF project via NuGet. But I am stuck with what to do next. I seem to be running into some outdated examples that use a global.asax instead of ServiceHostFactory. Is the ServiceHostFactory method the best one?
Where are the best current examples of Ninject usage with WCF? I'm unsure how to use the objects the Ninject WCF extension offers to do the wiring up.
More info:
I tried walking through - https://github.com/ninject/ninject.extensions.wcf/tree/Maintenance_2.2/src/Examples/WcfTimeService
My project was unable to resolve NinjectWcfApplication in the Global.asax.cs
This is why I thought this was no longer compatible or current with the latest Ninject.
If you are using service activations (no .svc file on disk) setup the ninject hosting factory in your web.config
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="MyService.svc" service="MyService" factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" />
</serviceActivations>
</serviceHostingEnvironment>
If you are using a .svc file you can edit the markup and add Factory="Ninject.Extensions.Wcf.NinjectServiceHostFactory" to the <%# ServiceHost ... %> declaration.
Then you need to modify your global.asax to inherit from the NinjectWcfApplication and create the Kernel
public class Global : NinjectWcfApplication
{
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
return kernel;
}
}
The link you provided is from 2.2 which is outdated. Just switch ob that page to the master branch
I haven't used Ninject but typically I begin the wire up process in the ServiceHost implementation. Something like:
public sealed class MyServiceHost : ServiceHost
{
public MyServiceHost() : base()
{
MyServiceLocator.SetAsDefaultServiceLocator();
}
}
I am trying to register a cross-AppDomain proxy with Autofac.
The concrete type represented by the proxy implements the interface IServiceHost. Thus, the proxy should also, in order to allow calls to the proxy using that interface to work.
I try to register the proxy with Autofac, by doing:
void Initialize(IServiceHost host)
{
Host = host;
var builder = new ContainerBuilder();
builder.RegisterInstance(host)
.As<IServiceHost>()
.SingleInstance();
Scope = builder.Build();
}
However, on the builder.Build() call, I get:
ArgumentException
The type 'System.MarshalByRefObject' is not assignable to service 'Treadmarks.Core.ServiceBase.IServiceHost'.
However, host is definitely an IServiceHost, since it isn't null and it comes from a strongly typed method argument.
Can anyone explain how I can register the proxy properly?
You should be able to use a lambda with the .Register() method, rather than .RegisterInstance(), to work around this.
Situation:
I have an interface, such as
public interface ITestClass
{
string StringElement { get; }
}
There is an implementation for it:
public class TestClassImplementor :
ITestClass
{
public string StringElement
{
get { return "AAA"; }
}
}
I do have a factory that creates an implementation instance:
public class TestClassFactory
{
public ITestClass Create()
{
return new TestClassImplementor();
}
}
I want to be able to resolve the implementation using Castle Windsor configuration file (XML), but at the same time not configuring the implementation for the interface.
Why is this needed: resolving (web) services. I do have a (web) service interface, but I don't access the implementation, as it is on another component. I want to be able to simply type MyCastleUtility.Resolve<ITestClass>() and get a prepared web service. I want to use Castle Windsor configuration file (XML) to configure the service I'm trying to access.
The problem: if I can't access the implementation, I can't configure it in the configuration file.
What I've tried so far:
1) Factories.
<component id="mycompfactory"
type="MyTestProject.TestClassFactory, MyTestProject"/>
<component id="mycomp"
type="MyTestProject.ITestClass, MyTestProject"
factoryId="mycompfactory" factoryCreate="Create" />
I do get the:
Castle.MicroKernel.ComponentRegistrationException : Type MyTestProject.INewTestClass is abstract. As such, it is not possible to instansiate it as implementation of MyTestProject.INewTestClass service
2) Proxies. Hit the wall when tried to find a way to configure that "proxy must be created for 'ITestClass' interface".
Target: configure Castle Windsor to create interface implementation without directly accessing the class, that implements the interface.
Help is much appreciated,
Mindaugas
For the factory approach:
Did you also configure the FactoryFacility in your config?
In your "mycomp", I think you want to use "service" and not "type":
<component id="mycomp" service="MyTestProject.ITestClass, MyTestProject" factoryId="mycompfactory" factoryCreate="Create" />