How to inject WCF Service Implementation into another WCF Service with Autofac - c#

I have multiple WCF Services hosted in IIS and configured with Autofac.
Global.asax
var builder = new ContainerBuilder();
builder.RegisterType<ServiceA>();
builder.RegisterType<ServiceB>();
builder.RegisterType<ServiceC>();
var container = builder.Build();
AutofacHostFactory.Container = container;
web.config
<system.serviceModel>
...
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
<serviceActivations>
<add service="ServiceA, MyServicesAssembly" relativeAddress="./ServiceA.svc" factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" />
<add service="ServiceB, MyServicesAssembly" relativeAddress="./ServiceB.svc" factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" />
<add service="ServiceC, MyServicesAssembly" relativeAddress="./ServiceC.svc" factory="Autofac.Integration.Wcf.AutofacServiceHostFactory, Autofac.Integration.Wcf" />
</serviceActivations>
</serviceHostingEnvironment>
<system.serviceModel>
Service Implementations
public class ServiceA : IServiceA
{
public ServiceA()
{
}
}
public class ServiceB : IServiceB
{
public ServiceB()
{
}
}
public class ServiceC : IServiceC
{
public ServiceC(IServiceA serviceA)
{
}
}
As you can see, ServiceC is different from the others and need an implementation of IServiceA.
Autofac can't resolve it, because there is no registration for IServiceA.
So I change the registration to this:
builder.RegisterType<ServiceA>().As<IServiceA>();
Autofac can now resolve ServiceC successfully, but the WCF hosting is not working anymore:
An exception of type 'System.ServiceModel.ServiceActivationException' occurred in mscorlib.dll but was not handled in user code
So my question is:
Is there a way that I can have both, a hosted WCF Service instance, and the possibility to pass a Service Implementation to another Service? All configured with AutoFac?
I'm also thinking of a workaround, but everything that comes to my mind results in a huge effort.
I know that these services needs to be refactored, so that there is no need to pass in another "service". But this is a different story.

If you want to expose a component as a set of services as well as
using the default service, use the AsSelf method:
//...
builder.RegisterType<ServiceA>()
.AsSelf() //<--
.As<IServiceA>();
//...
This will associate the class and interface together so that IServiceA can be injected as needed and it will be resolved to ServiceA. This also allow the WCF to not break as ServiceA is registered.
Reference Autofac Documentation: Registration Concepts

Related

Use Autofac with a WCF service using WAS

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.

Autofac - Unable to get Interceptor working on service

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.

IIS hosting for WCF service with 2 contracts or hosting 2 services with dependencies

I'm developing a WCF service that has a contract called MyApp.IOperationService.
<service name="MyApp.OperationService">
<endpoint address="OperationService" binding="basicHttpBinding" contract="MyApp.IOperationService" />
</service>
For the service behaviour I used InstanceContextMode = InstanceContextMode.Single and ConcurrencyMode = ConcurrencyMode.Multiple because the application uses a shared physical resource.
I needed an administrative interface for this service and first I added a new contract within the same service. This approach didn't appeal to me because the administrative contract was exposed, through the metadata, to the clients using the operation contract.
Then I opted for creating another service altogether.
<service name="MyApp.AdminService">
<endpoint address="Admin" binding="netTcpBinding" contract="MyApp.IAdminService" />
</service>
This service has one operation, called Login, that propagates the pincode to the OperationService object.
namespace MyApp
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single, UseSynchronizationContext = false)]
public class AdminService : IAdmin
{
MyApp.OperationService objOperationService = null;
public AdminService(MyApp.OperationService objOperationService)
{
m_objOperationService = objOperationService;
}
public void Login(string pincode)
{
m_objOperationService.Login(pincode);
}
}
}
In a self-hosting environment I create a MyApp.OperationService object, then pass this object to the constructor of MyApp.AdminService. For IIS hosting, I discovered that I need to use WCF extensibility points and implement an IInstanceProvider, then use a ServiceHostFactory.
At this point I stopped and wondered if this will work at all, given that my AdminService expects an already created MyApp.OperationService that IIS controls, and it already seems awfully complicated for my humble purpose.
The question is if this (administrative contract/interface for an existing service that is not exposed through the metadata) can be achieved in another way?
Thank you.
I couldn't find a way to solve the problem, except using WCF extensibility points. I used Microsoft.Practices.Unity to manage the services through IoC, then used the Factory property in the .svc file.

Ninject and WCF - Correct method to initialize the Inversion of Control Container

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();
}
}

Castle Windsor: XML Configuration for Dynamic Proxy without a Target

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" />

Categories

Resources