I have created a WebApi application, which uses SimpleInjector.
Now a user of the API wants a WCF endpoint to consume it (for whatever reason).
To make things more simple for me, I want to just call the WebApi controller from inside the WCF service:
public class MyService : IMyService
{
private MyApiController controller;
public MyService(IMyInjection inject)
{
controller = new MyApiController(inject);
}
public int GetResult(string data)
{
return controller.GetResult(data);
}
}
To make it work in WebApi, my controller currently uses an injection with a WebApiRequestLifeStyle
lifestyle, and I have tried to "just add" SimpleInjector WCF Integration :
public static void LoadDependencyInjection()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
// some more registration
// configure WCF to use SimpleInjector
container.RegisterWcfServices(Assembly.GetExecutingAssembly());
// verify
container.Verify();
// configure the global WebApi to use SimpleInjector
GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
// configure WCF to use SimpleInjector
SimpleInjectorServiceHostFactory.SetContainer(container);
}
Obviously, the WCF service does not like the WebApi lifestyle, and throws an error when I try to call a method:
The ITransferOrderRequest is registered as 'Web API Request' lifestyle, but the instance is requested outside the context of a Web API Request.
I have tried to create a second container with a different lifestyle:
public static void LoadDependencyInjection()
{
// WebApi container
var webApiContainer = CreateContainer(new WebApiRequestLifestyle(true));
webApiContainer.RegisterWebApiControllers(GlobalConfiguration.Configuration);
webApiContainer.EnableHttpRequestMessageTracking(GlobalConfiguration.Configuration);
// WCF container
var wcfContainer = CreateContainer(new WcfOperationLifestyle(true));
wcfContainer.RegisterWcfServices(Assembly.GetExecutingAssembly());
// verify
webApiContainer.Verify();
wcfContainer.Verify();
// configure the global WebApi to use SimpleInjector
GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(webApiContainer);
// configure WCF to use SimpleInjector
SimpleInjectorServiceHostFactory.SetContainer(wcfContainer);
}
private static Container CreateContainer(ScopedLifestyle lifestyle)
{
var container = new Container();
// set the default lifestyle
container.Options.DefaultScopedLifestyle = lifestyle;
// here I register a bunch of interfaces/instances using the Scoped lifestyle
return container;
}
But the second call to container.Options.DefaultScopedLifestyle = lifestyle;
(using WcfOperationLifestyle
) also changes the the default lifestyle of the first container! In this case, when I call my WebApi service I get the same kind of error, but in reverse:
IMyStuff is registered as WCF operation lifestyle.
I have seen that there is a Hybrid lifestyle, but I have no idea how to detect whether it's currently a WCF or WebApi request...
Thanks!
I have no idea how to detect whether it's currently a WCF or WebApi request...
You can check whether the request is a WCF request by checking whether OperationContext.Current != null
.
var lifestyle = Lifestyle.CreateHybrid(
lifestyleSelector: () => OperationContext.Current != null,
trueLifestyle: new WcfOperationLifestyle(true),
falseLifestyle: new WebApiRequestLifestyle()
);
I don't know "what I lose by just newing up a controller".
To clear up my suggestion in comments, I understand where you are coming from. It's still my opinion that you should consider doing this over HTTP before totally ruling it out. You can overcome the "hardwire routes" problem by making the URL part of the WCF project's app.config. There is some decent config transforms tooling you can use to generate different routes for different environments. Changing config to modify program behavior is loosely coupled, and highly cohesive.
It is a bit less efficient, but I would argue the cost may be justified if the actual additional latency is small enough. The things you lose are all of the WebAPI request pipeline benefits added to the controller, such as content negotiation, filters, etc. Since you didn't post any of that code and are OK with your decision, I assume you are really only after the GetResults(string data)
method body with its scoped dependencies, and have no need for anything else.
However be aware that your decision creates a tighter coupling between the WCF service and the WebAPI controller than an HTTP network call would.