Search code examples
c#simple-injector

Controller disposal in IHttpControllerActivator


I have a custom IHttpControllerActivator for my web api controllers which I'm using along with simple injector:

public sealed class ApiControllerActivator : IHttpControllerActivator
{
    private readonly Container _container;
    private readonly IHttpControllerActivator _original;

    public ApiControllerActivator(Container container, IHttpControllerActivator original)
    {
        _container = container;
        _original = original;
    }

    public IHttpController Create(HttpRequestMessage request,
                        HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        var controller = CreateController(request, controllerDescriptor, controllerType);
        // request.RegisterForDispose(...); required?
        return controller;
    }

    private IHttpController CreateController(HttpRequestMessage request, 
                        HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        if (controllerType.IsSubclassOf(typeof(WebApiController)))
        {
            return (IHttpController) _container.GetInstance(controllerType);
        }

        return _original.Create(request, controllerDescriptor, controllerType);
    }
}

Registration:

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

Do I need to handle any disposal of the controller, or is it handled by the framework?


Solution

  • Do I need to handle any disposal of the controller

    The short answer is: as long as you register your Web API controllers using the RegisterWebApiControllers() extension method, you do not need to handle the disposal of your controllers.

    The long answer is that when you call RegisterWebApiControllers, Simple Injector will actually not dispose your controllers at all, but you will get a VerificationException when you override Dispose(bool) in one of your controllers when you call Container.Verify().

    The reasoning is as follows: Simple Injector will only dispose of disposable classes when they are registered as either Scoped or Singleton. Transient registrations are never disposed. The RegisterWebApiControllers extension method, however, registers controllers as Transient.

    When registering a disposable Transient in Simple Injector, it would typically cause a DisposableTransientComponent warning, when Verify is called. Since, however, the ApiController base class does implement IDisposable, but its Dispose(bool) method is a no-op, not disposing it is not be a problem, unless the derived controller explicitly overrides Dispose(bool).

    Because of that, RegisterWebApiControllers simply suppresses this warning when it makes the registration. When it finds that the derived controller class does override Dispose(bool), however, it will discard the suppression and you will see Verify() warn you about this disposable type, because not disposing such type would be a problem.

    The idea behind this behavior is that the need to actually implement disposable logic on a controller would be really rare, because a controller itself would typically not have to deal with unmanaged resources. This is typically something that lower level components will do, but, when registered correctly, those components will be disposed by Simple Injector. If you have a controller that has dispose logic, you should consider refactoring it and moving that resource out of the controller, into a different component.

    In the extremely rare case that having dispose logic on a controller itself makes the most sense, you will either have to:

    • Register that particular controller as Scoped
    • Or suppress the warning on that controller and register that controller for disposal in the request's active Scope using container.RegisterInitializer<MyControllerType>(c => Lifestyle.Scope.RegisterForDisposal(container, c));