IoC: Castle Windsor and WebAPI - c#

I have an MVC4 site using Castle Windsor that I want to add some WebAPI calls to, so I start digging around a little bit on the interwebs.
Now I don't know the ins and outs of IoC; I followed a tutorial for how to set up Castle Windsor on my project, injecting the IUnitOfWorkFactory and the IApplicationService as public properties in a base controller, and a few other interfaces as needed in the controller constructors. It works swimmingly, so I've never had to do more with it.
Everywhere that I'm reading up on WebAPI, I'm told DI will not work so well using Castle Windsor, talking about problems with the IDependencyResolver and IDependencyScope. There are several workarounds and implementations of how to get around this problem, but what is not clear to me is what exactly the problem is. Code snippets are included, but the assumption is you know what class they belong to, and how they are invoked, which unfortunately I do not. Additionally, all the examples I've seen online refer to an exclusive WebAPI project, and not an MVC4 project with a couple ApiControllers judiciously tossed in. I don't know how, or if, this affects anything.
Why won't what I have working with my standard controllers not work with an API controller? What kind of code acrobatics need to do to get WebAPI calls and standard web calls to work in the same application?

Existing Castle Windsor MVC configuration
Assuming you have MVC and Castle Windsor setup similarly to the Castle Windsor MVC tutorial, adding IoC to get Web API controllers to utilize dependency injection is very simple with Mark Seemann's post (note that he explains why not to use IDependencyResolver).
From the Castle Windsor tutorial you should have something like this in Global.asax.cs.
private static IWindsorContainer container;
protected void Application_Start()
{
//... MVC / Web API routing etc.
BootStrapper bs = new BootStrapper();
container = bs.ConfigureCastleWindsorMVC();
}
BootStrapper.ConfigureCastleWindsorMVC() snip
IWindsorContainer container = new WindsorContainer()
.Install(
new LoggerInstaller()
//...,
, new ControllersInstaller()
);
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
return container;
Required changes
From Mark Seemann's post you need to get into Web API's entry point (Composition Root) through the IHttpControllerActivator. Here's his adapter implementation which you need.
public class WindsorCompositionRoot : IHttpControllerActivator
{
private readonly IWindsorContainer container;
public WindsorCompositionRoot(IWindsorContainer container)
{
this.container = container;
}
public IHttpController Create(HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller =
(IHttpController)this.container.Resolve(controllerType);
request.RegisterForDispose(
new Release(() => this.container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action release;
public Release(Action release) { this.release = release; }
public void Dispose()
{
this.release();
}
}
}
With the IHttpControllerActivator adapter and the MVC Castle Windsor container implementation, you just need to configure it in the Global.asax.cs (or in BootStrapper if you used that). It has to be after the MVC initialization since the MVC initialization has all of the installers.
private static IWindsorContainer container;
protected void Application_Start()
{
// MVC / Web API routing etc.
BootStrapper bs = new BootStrapper();
container = bs.ConfigureCastleWindsorMVC();
// Web API Castle Windsor ++ ADD THIS ++
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new WindsorCompositionRoot(container));
}
Final Result:
The Web API controllers can use your injected dependencies the same as your MVC controllers.
public class TestController : ApiController
{
private readonly ITestService TestService;
public TestController(ITestService testService)
{
this.TestService = testService;
}
// GET api/<controller>
public IEnumerable<string> Get()
{
return TestService.GetSomething();
//return new string[] { "value1", "value2" };
}
}

In order to use Windsor with webapi follow
http://blog.ploeh.dk/2012/10/03/DependencyInjectioninASP.NETWebAPIwithCastleWindsor/
(BEH: fixed link)
Read also
Castle Windsor/DelegatingHandler/IPrincipal Dependency Injection (DI)/Inversion of Control (IoC) in ASP.NET Web API
You can use webapi and MVC controllers in the same app (I prefer to keep it separate) but routing and controllers factory are different and you have to set up two different configuration and handle routing overlaps...
For MVC & Windsor you can find a great

The following sample project gave me the answer I was looking for. It uses Castle Windsor for dependency injection. I was able to use MVC Controllers alongside Web API controllers on the same Application.
mirajavora / WebAPISample
Here's the post detailing it:
Getting Started with ASP.NET Web API

First as Iko stated you need to create a class that implements IHttpControllerActivator.
Then in ContainerBootstrapper in Bootstrap() add the following Replace the default with the one implemented:
//This will help in creating Web api with Dependency injection
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new WindsorCompositionRoot(container));
Lastly which is not mentioned here and it didn't work for me without it that you should add the following in you implemented IWindsorInstaller service inside install() :
container.Register(
Classes.FromThisAssembly()
.BasedOn<ApiController>()
.LifestyleTransient()
);

Related

ASP.NET Core 2.1 Service Locator with Simple Injector returning null

I have an .NET MVC 5 .NET Framework Application which I am converting to .NET Core 2.1
I have a custom action filter which in .NET Framework version was registered as a Global Filter in a Filterconfig class like below:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyCustomActionFilter());
}
}
Within the custom action filter in the .NET version I was using Service Locator pattern (I know it can be considered an anti pattern) as below:
var myService = DependencyResolver.Current.GetService<IMyService>();
I am using Simple Injector for DI and everything works fine in the .NET Version. With the .NET Core version I am trying to get the same functionality working but myService is always null
I am still using Simple Injector (as all the other projects in the solution use it and they are not getting move to .NET Core projects (only the web one is).
My Startup.cs class has this code:
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new MyCustomActionFilter());
});
SimpleInjectorConfig.IntegrateSimpleInjector(services, container);
At my service layer I have a SimpleInjector Registartion class that gets called from Web Layer - it then calls down to DAL Layer to do Registration
public class SimpleInjectorRegistration
{
public static void RegisterServices(Container container)
{
container.Register<IMyService, MyService>();
//further code removed for brevity
When I run the application with a breakpoint in the Custom Filter and a breakpoint in this RegisterServices method I can see the breakpoint in the RegisterServices method gets hit first and then the breakpoint in the Custom Filter - this made me think everything was wired up in the container correctly.
However I am trying to do the below again in the custom filter with .NET Core Service Locator pattern
var myService = filterContext.HttpContext.RequestServices.GetService<IMyService>();
but the result is always null?
Is there something I have missed in this setup?
------------ UPDATE -------------------
Based on Stevens comment I added a constructor to my action filter and passed in the Simple Injector container.
So My Startup class now is:
public class Startup
{
//Simple Injector container
private Container container = new Container();
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new MyCustomActionFilter(container));
My Custom filter now is like below with constructor added:
public class MyCustomActionFilter : ActionFilterAttribute
{
private readonly IMyService _myService;
public MyCustomActionFilter(Container container)
{
_myService = container.GetService<IMyService>();
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//actual code of custom filter removed - use of MyService
I set a breakpoint on the Constructor of MyCustomActionFilter and I can see it getting hit but I get an Error thrown:
SimpleInjector.ActivationException: 'The IDbContext is registered as 'Async Scoped' lifestyle, but the instance is requested outside the context of an active (Async Scoped) scope.'
MyService has a Dependency on the DbContext which is injected into it (it is doing work saving and retrieving data from DB.
For the DB Context I registered it as below:
public class SimpleInjectorRegistration
{
public static void RegisterServices(Container container, string connectionString)
{
container.Register<IDbContext>(() => new MyDbContext(connectionString),
Lifestyle.Scoped);
}
}
There are some significant changes between how to integrate Simple Injector in the old ASP.NET MVC and the new ASP.NET Core. In the old system, you would be able to replace the IDependencyResolver. ASP.NET Core, however, contains a completely different model, with its own internal DI Container. As it is impossible to replace that built-in container with Simple Injector, you will have the two containers run side-by-side. In that case the built-in container will resolve framework and third-party components, where Simple Injector will compose application components for you.
When you call HttpContext.RequestServices.GetService, you will be requesting the built-in container for a service, not Simple Injector. Adding the IMyService registration to the built-in container, as TanvirArjel's answer suggests, might seem to work at first, but that completely skips Simple Injector from the equation, which is obviously not an option, as you wish to use Simple Injector as your application container.
To mimic the Service Locator-like behavior you had before, you will have to inject the SimpleInjector.Container into your filter, as follows:
options.Filters.Add(new MyCustomActionFilter(container));
It would be an error, however, to call the container from within the constructor, as you are showing in your question:
public class MyCustomActionFilter : ActionFilterAttribute
{
private readonly IMyService _myService;
public MyCustomActionFilter(Container container)
{
_myService = container.GetService<IMyService>(); // NEVER DO THIS!!!
}
...
}
WARNING: You should never resolve from the container from the constructor. Or in more general: you should never use any injected dependency from inside the constructor. The constructor should only store the dependency.
As Mark Seemann explained, injection constructors should be simple. In this case, it even gets worse because:
During the time that the constructor of MyCustomActionFilter is invoked, there is no active scope, and IMyService can't be resolved
Even if IMyService could be resolved, MyCustomActionFilter is a Singleton and storing IMyService in a private field will cause a hidden Captive Dependency. This could lead to all sorts of trouble.
Instead of storing the resolved, IMyService dependency, you should store the Container dependency:
public class MyCustomActionFilter : ActionFilterAttribute
{
private readonly Container _container;
public MyCustomActionFilter(Container container)
{
_container = container;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
myService = container.GetService<IMyService>();
//actual code of custom filter removed - use of MyService
}
}
During the time that OnActionExecuting is called, there will be an active Simple Injector Scope, which will allows IMyService to be resolved. On top of that, as IMyService is not stored in a private field, it will not be cached and will not cause a Captive Dependency.
In your question you referred to the Service Locator anti-pattern. Whether or not the injection of the Container into your filter is in fact an implementation of the Service Locator anti-pattern depends on where the filter is located. As Mark Seemann puts it:
A DI container encapsulated in a Composition Root is not a Service Locator - it's an infrastructure component.
In other words, as long as the filter class is located inside your Composition Root, you are not applying the Service Locator anti-pattern. This does mean, however, that you must make sure that the filter itself contains as little interesting behavior as possible. That behavior should all be moved to the service that the filter resolves.
As #Steven points out, the built-in container will resolve framework and third-party components, where Simple Injector will compose application components for you. For built-in container, it could not resolve the service from simple injector. For simple injector, you could try EnableSimpleInjectorCrossWiring to resolve services from built-in container.
For options.Filters.Add, it also accepts MyCustomActionFilter instance, without resigering Container as depedence into MyCustomActionFilter, you could try register MyCustomActionFilter in sample injector, and then pass this instance to options.Filters.Add.
Register Services
private void InitializeContainer(IApplicationBuilder app)
{
// Add application presentation components:
container.RegisterMvcControllers(app);
container.RegisterMvcViewComponents(app);
// Add application services. For instance:
container.Register<IMyService, MyService>(Lifestyle.Scoped);
container.Register<MyCustomActionFilter>(Lifestyle.Scoped);
// Allow Simple Injector to resolve services from ASP.NET Core.
container.AutoCrossWireAspNetComponents(app);
}
add MyCustomActionFilter
services.Configure<MvcOptions>(options =>
{
using (AsyncScopedLifestyle.BeginScope(container))
{
options.Filters.Add(container.GetRequiredService<MyCustomActionFilter>());
}
});
#region SampleInjector
IntegrateSimpleInjector(services);
#endregion
Note If you specify container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();, you will need using (AsyncScopedLifestyle.BeginScope(container)) when you call container.GetRequiredService<MyCustomActionFilter>().

MVC API controller error with dependency injection

i have a simple controller where i am using the interfaec like this ,
public class HomeController : Controller
{
// GET: Home
private IHotelService hotelService;
public HomeController(IHotelService _hotelService)
{
hotelService = _hotelService;
}
}
its working fine, but when i use same thing with API controller like
public class RoomController : BaseApiController
{
private IHotelService hotelService;
public RoomController(IHotelService _hotelService)
{
hotelService = _hotelService;
}
it gives me error
As pointed out here (and in several other answers on SO), you have most likely not registered your DI container with Web API. Web API is a separate framework than MVC and therefore it has a separate configuration, including dependency injection.
So, you need to set
GlobalConfiguration.Configuration.DependencyResolver = MyDependencyResovler(container);
at application startup. The details of how to do this depend on what container you are actually using and whether you use a stock dependency resolver or roll your own as shown in Dependency Injection in ASP.NET Web API 2.

Can't inject a delegate using ASP.NET Core DI

Say I've a MVC Core Controller like this:
public class SomeController
{
public SomeController(IConfiguration appConfig, Func<string> someDelegate)
{
}
}
Also, I'm using AutoFac to resolve injections. Object injections are working flawlessly while adding a delegate injection produces an ASP.NET Core exception which tells that Func<string> can't be injected because there's no component to inject with such type.
When I try to manually resolve SomeController using AutoFac I get the desired behavior.
Is there any way to support this scenario without using AutoFac to resolve controllers?
Controllers are not resolved via DI by default, they are constructed in the DefaultControllerFactory or so.
Update
Microsoft.Extensions.DependencyInjection doesn't support named components, discovery, auto registrations, decorators etc.
It's meant to be simple out of the box IoC and provide the base for DI for basic applications and offer easy way for 3rd party IoC containers (with advanced features such as auto discovery, decorators etc.) to be integrated (basically all they need is process the information in IServiceCollection and return their own implementation of IServiceProvider from Configure method).
Tag helpers, controllers and view components are different in this aspect as they have their own activators (the default one use activation utilities, which at some point further down the pipeline use the service provider). For that reasons AddControllersAsServices exists, because it replaces DefaultControllerActivator (which uses ActivationUtilities, see DefaultControllerActivator.cs) with ServiceBasedActivator (which uses IServiceProvider, see ServiceBasedControllerActivator).
Also see this related answer for details on how to resolve controllers, tag helpers and view components via DI.
var builder = services
.AddMvc()
.AddControllersAsServices() // this one for your case
.AddViewComponentsAsServices()
.AddTagHelpersAsServices();
I was just run into this issue myself so I thought I would share for future reference as I had one case where I wanted to resolve a delegate but including an additional library seemed like overkill.
Given the following defintions:
public interface ISomething { /*...*/ };
public interface ISomeService { /*...*/ }
public class SomeService : ISomeService { /*...*/ }
public class Something
{
public Something(ISomeService service, string key) { /*...*/ }
}
// I prefer using a delegate for readability but you
// don't have to use one
public delegate ISomething CreateSomething(string key);
The delegate can be registered like this:
var builder = services
.AddSingleton<ISomeService, SomeService>()
.AddTrasient<CreateSomething>(provider => key => new Something(provider.GetRequiredService<ISomeService>(), key));

Register custom controller in runtime

I've some api controller that i want to register at runtime in my mvc application.
The controller itself resides into Class Library project and looks like:
public class CustomController : ApiController
{
public string Get()
{
return "Hello";
}
}
I've compile that library (gave it a name Injection.dll), and in my mvc app try to register those controller via Unity.Mvc library container
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
Assembly customLogicAssembly = Assembly.LoadFrom(HttpContext.Current.Server.MapPath("~/bin/" + "Injection.dll"));
Type existingType = customLogicAssembly.GetTypes().First();
container.RegisterType(existingType);
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
So it seems that registration works fine and i have no errors while debuggig it, but
i don't have expected result, when i navigate to api/Custom/Get i have an The resource cannot be found. error in browser.
Pls help what i miss here.
MVC and Web API have each its own dependency resolver.
Your code is registering the MVC Dependeny Resolver:
DependencyResolver.SetResolver(yourResolver);
What you need to register is the Web API Dependency resolver, like this:
GlobalConfiguration.Configuration.DependencyResolver = yourResolver;
The expected resolver in both cases must implement IDependencyResolver, but it serves a different purpose.
It's not recommended that you share the same dependency resolver (thus container and composition root) for both things. If you need to do so, use two different instances of IDependencyResolver and register the controllers where they belong.
IMPORTANT NOTE
There are two different IDependencyResolver interfaces, one for MVC, and the other for Web API. They have the same name, but are on different namespaces. And you need to implement the appropriate for each case (or both, if you need to implement DI for both MVC and Web API):
System.Web.Mvc.IDependencyResolver, for MVC
System.Web.Http.Dependencies.IDependencyResolver, for Web API

Using dependency injection with an ApiController when it also needs an empty constructor?

I have an ApiController in an Area of my MVC website, I'm injecting dependencies into it via Unity and my controllers extend the System.Web.Http.ApiController.
I'm using Unity from Microsoft.Practices.Unity.dll, v3.0.0.0.
I can route to the controller with the following in ApiAreaRegistration
context.MapRoute(
"Api_default",
"Api/users/{action}/{id}"
);
But I get the following error :
Type 'Project.Areas.Api.Controllers.UsersController' does not have a default constructor
However if I add a default constructor my dependencies don't get resolved.
I'm beginning to feel like I'm missing something structural?
You don't show your controller registration and the error message suggests you have not registered the controller dependencies.
I use the Unity.WebAPI NuGet package to take care of the controller build-up and container lifetime management. If your project also uses MVC controllers the Unity.Mvc3 will handle those controllers. These packages get Unity wired-up for my controllers with very little code.
My Unity bootstrap looks like this
public static class UnityConfig
{
var container = BuildUnityContainer();
// MVC controllers
DependencyResolver.SetResolver(new Unity.Mvc3.UnityDependencyResolver(container));
// WebAPI controllers
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// you don't need to register controllers
container.RegisterType<IUsersService, UsersService>();
...
return container;
}
And I don't worry about my controller creation -- It just works.
public class UsersController : ApiController
{
private IUsersService service;
public UsersController(IUsersService service)
{
this.service = service;
}
...
}
GlobalConfiguration.Configuration.DependencyResolver =
new UnityDependencyResolver(YOUR_UNITY_CONTAINER);
and from http://msdn.microsoft.com/en-us/library/dn178463(v=pandp.30).aspx#sec18 you can find that you should search for 'Unity bootstrapper for ASP.NET WebApi' and you get the UnityDependencyResolver from the namespace: 'Microsoft.Practices.Unity.WebApi'.
Easiest way is just to install the WebApi Bootstrapper and look in the App_Start folder.

Categories