Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolve dependencies in ASP.NET Web API with Simple Injector and IHttpControllerActivator

I am currently using Simple Injector to resolve dependencies into my Asp.Net Web Api projects.

From the documentation you can configure it like that:

protected void Application_Start() {
    // Create the container as usual.
    var container = new Container();
    container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();

    // Register your types, for instance using the scoped lifestyle:
    container.Register<IUserRepository, SqlUserRepository>(Lifestyle.Scoped);

    // This is an extension method from the integration package.
    container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

    container.Verify();

    GlobalConfiguration.Configuration.DependencyResolver =
        new SimpleInjectorWebApiDependencyResolver(container);

    // Here your usual Web API configuration stuff.
}

The main points here are to register the Web Api controllers and set a custom dependency resolver.

However I've just read these article from Mark Seemann on how to configure dependency injection in Asp.Net Web Api:

  • Dependency Injection and Lifetime Management with ASP.NET Web API
  • Dependency Injection in ASP.NET Web API with Castle Windsor

From these articles, I've learnt that there is a better option than implementing IDependencyResolver to resolve Web Api dependencies. This other option is to create an implementation of the IHttpControllerActivator that acts as an Adapter over the IoC Container.

Here is the implementation I've coded using SimpleInjector:

public class SimpleInjectorControllerActivator : IHttpControllerActivator
{
    private readonly Container _container;

    public SimpleInjectorControllerActivator(Container container)
    {
        _container = container;
    }

    public IHttpController Create(HttpRequestMessage request,
        HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        request.RegisterForDispose(_container.BeginExecutionContextScope());

        return (IHttpController)_container.GetInstance(controllerType);
    }
}

and in the Application_Start method, I've replaced this line:

GlobalConfiguration.Configuration.DependencyResolver =
    new SimpleInjectorWebApiDependencyResolver(container);

by this line :

GlobalConfiguration.Configuration.Services.Replace(
    typeof(IHttpControllerActivator),
    new SimpleInjectorControllerActivator(container));

I would like to know if the implementation of the IHttpControllerActivator is valid and also if this approach is valid and will work as good as the normal one ?

like image 999
Thomas Avatar asked Apr 14 '16 03:04

Thomas


1 Answers

Yes, your implementation is valid.

Only be careful not to use both the SimpleInjectorWebApiDependencyResolver and the SimpleInjectorControllerActivator in the same application. Both start an ExecutionContextScope which could lead to having two scopes within the same web request, so they are mutually exclusive.

A general advantage of using a controller activator over the dependency resolver is that the dependency resolver contract forces the adapter to return null when a service can't be created. This is a very common problem that developers run into, and it often causes the confusing controller does not have a default constructor exception. This problem does not exist when using an IHttpControllerActivator, since the contract forces you to return a value or throw an exception.

The Simple Injector Web API integration project however, prevents this problem with dependency resolver, by never returning null (but throwing an exception instead) in case the requested service is an API controller (and thereby implicitly breaking the IDependencyResolver's contract).

An advantage of using the SimpleInjectorDependencyResolver is that it becomes easier to create message handlers that operate within the execution context scope, since you can trigger the creation of this scope by calling request.GetDependencyScope() method. With the current implementation, the scope just gets started at the time that the controller gets created, which is after you run the handlers. Changing this isn't that hard, but involves changing your controller activator and have an outermost handler that starts the execution context scope (or again falling back on a dependency resolver that manages the execution context scope).

One of the arguments of Mark Seemann is that it becomes hard to pass context around, which is a very valid point, as long as your components don't require this context during construction. But this is not a problem you'll experience when using Simple Injector, because there is an extension method that helps you with accessing the HttpRequestMessage. So although the IDependencyResolver abstraction isn't designed for getting the contextual information, there are ways to get this contextual information.

In the past we decided to go with an adapter for the IDependencyResolver, mainly because this was the common practice with all DI containers. I partly regret this decision, but using the SimpleInjectorDependencyResolver is now usually the easiest way of plugging in Simple Injector into Web API. We considered adding a SimpleInjectorControllerActivator as well, but this had no practical benefit for most users, while we still would had to document when to use what. So we decided to stick with the dependency resolver adapter; an adapter for the activator is easily created for anyone who needs it, as you can see.

For ASP.NET Core however, we went into a different direction, and as you can see in the documentation, the integration package actually contains a SimpleInjectorControllerActivator out of the box. In ASP.NET Core, the controller activator is the perfect interception point and due to the OWIN-like pipeline, a scope can be easily wrapped around a request. So with ASP.NET Core, the advised practice is to use the controller activator as interception point.

like image 72
Steven Avatar answered Oct 25 '22 18:10

Steven