Written by 15:45 Containers, Tools & technologies

Single IoC Container in the HTTP-request: Web API vs. OWIN Middleware

In this article, I am going to provide you with a working solution that allows you to have a single dependency container (IoC container) during the whole query life cycle, as well as to control its creation and disposal.

You may find it useful when a web-application should possess a transactionality, which is, in my opinion, a must-have for any web application. In other words, the changes are stored in the database only if the request is successfully processed and canceled if there is an error in any of the steps. The error indicates an incorrect result and uncontrolled effects (github source code).

Theory

Web API 2 projects are configured by using the OWIN IAppBuilder interface designed to help build an incoming request processing pipeline.

The picture illustrates a query lifecycle. It passes through all the components of the chain, and then goes into the Web API (which is also a separate component) and returns back with the response from the server.

To have a single dependency container, it is necessary to create it explicitly when starting to process the query and to dispose it upon completion:

  1. Starting to process a query.
  2. Creating a container.
  3. Using the container in middleware.
  4. Using the container in Web API.
  5. Disposing the container.
  6. Completing the query processing.

To do this, we need to configure the container and register it in Web API using DependencyResolver:

// Configure our parent container
var container = UnityConfig.GetConfiguredContainer();
            
// Pass our parent container to HttpConfiguration (Web API)
var config = new HttpConfiguration {
    DependencyResolver = new UnityDependencyResolver(container)
};

WebApiConfig.Register(config);

We need to create our own middleware, which will create a child container:

public class UnityContainerPerRequestMiddleware : OwinMiddleware
{
    public UnityContainerPerRequestMiddleware(OwinMiddleware next, IUnityContainer container) 
       : base(next)
    {
        _next = next;
        _container = container;
    }

    public override async Task Invoke(IOwinContext context)
    {
        // Create child container (whose parent is global container)
        var childContainer = _container.CreateChildContainer();

        // Set created container to owinContext 
        // (to become available at other places using OwinContext.Get<IUnityContainer>(key))
        context.Set(HttpApplicationKey.OwinPerRequestUnityContainerKey, childContainer);

        await _next.Invoke(context);

        // Dispose container that would dispose each of container's registered service
        childContainer.Dispose();
    }

    private readonly OwinMiddleware _next;
    private readonly IUnityContainer _container;
}

Then, we can use it in other middleware. In my implementation, I save the container in the global OwinContext class using context.Set that is passed to each subsequent middleware and get it using context.Get:

public class CustomMiddleware : OwinMiddleware
{
    public CustomMiddleware(OwinMiddleware next) : base(next)
    {
        _next = next;
    }

    public override async Task Invoke(IOwinContext context)
    {
        // Get container that we set to OwinContext using common key
        var container = context.Get<IUnityContainer>(
                HttpApplicationKey.OwinPerRequestUnityContainerKey);

        // Resolve registered services
        var sameInARequest = container.Resolve<SameInARequest>();

        await _next.Invoke(context);
    }

    private readonly OwinMiddleware _next;
}

Problem

Middleware Web API contains its custom query processing cycle, which is as follows:

  1. A query gets into HttpServer to start processing HttpRequestMessage and passing it to the routing system.
  2. HttpRoutingDispatcher retrieves data from the query and determines a controller responsible for processing using Route tables.
  3. HttpControllerDispatcher creates a previously defined controller and calls query processing method to form HttpResponseMessage.

In DefaultHttpControllerActivator, the following row creates a controller.

IHttpController instance = (IHttpController)request.GetDependencyScope().GetService(controllerType);

The main content of the GetDependencyScope method is as follows:

public static IDependencyScope GetDependencyScope(this HttpRequestMessage request) {
    // …

    IDependencyResolver dependencyResolver = request.GetConfiguration().DependencyResolver;
    result = dependencyResolver.BeginScope();

    request.Properties[HttpPropertyKeys.DependencyScope] = result;
    request.RegisterForDispose(result);    

    return result;
}

The Web API requests Dependencyresolver, which we have registered in HttpConfiguration and creates a child container using dependencyResolver.BeginScope(). Within this container, an instance will be created, responsible for processing the controller request.

The containers we use in our middleware and Web API are not the same ones. Moreover, they are located at the same nesting level, where the global container is their parent.

Thus, the global container is:

  1. A child container created in UnityContainerPerRequestMiddleware.
  2. A child container created in Web API.

It is logically correct for the Web API when it is the only place to process a request.  A container is created at the beginning and disposed at the end.

However, Web API is currently a part of the pipeline, which means that you will have to refuse from the idea to create your custom container. Our task is to redefine this behavior and specify a container, in which Web API needs to create controllers and to resolve dependencies.

Solution

To resolve the task, we can implement our own IHttpControllerActivator. In the Create method, we will get a previously created container and resolve dependencies:

public class ControllerActivator : IHttpControllerActivator
{
    public IHttpController Create(
        HttpRequestMessage request,
        HttpControllerDescriptor controllerDescriptor,
        Type controllerType
    )
    {
        // Get container that we set to OwinContext using common key
        var container = request.GetOwinContext().Get<IUnityContainer>(
                HttpApplicationKey.OwinPerRequestUnityContainerKey);

        // Resolve requested IHttpController using current container
        // prevent DefaultControllerActivator's behaviour of creating child containers 
        var controller = (IHttpController)container.Resolve(controllerType);

        // Dispose container that would dispose each of container's registered service
        // Two ways of disposing container:
        // 1. At UnityContainerPerRequestMiddleware, after owin pipeline finished (WebAPI is just a part of pipeline)
        // 2. Here, after web api pipeline finished (if you do not use container at other middlewares) (uncomment next line)
        // request.RegisterForDispose(new Release(() => container.Dispose()));

        return controller;
    }
}

To use it in Web API, we need to replace a standard HttpControllerActivator implementation in the configuration:

var config = new HttpConfiguration {
    DependencyResolver = new UnityDependencyResolver(container)
};

// Use our own IHttpControllerActivator implementation 
// (to prevent DefaultControllerActivator's behaviour of creating child containers per request)
config.Services.Replace(typeof(IHttpControllerActivator), new ControllerActivator());

WebApiConfig.Register(config);

Thus, we get the following mechanism of working with our single container:

  1. Starting to process a query
  2. Creating a child container inherited from the global one:
    var childContainer = _container.CreateChildContainer();
  3. Assigning a container in OwinContext:
    context.Set(HttpApplicationKey.OwinPerRequestUnityContainerKey, childContainer);
  4. Using a container in other middleware:
    var container = context.Get<IUnityContainer>(HttpApplicationKey.OwinPerRequestUnityContainerKey);
  5. Using a container in Web API:
    5.1. Getting a controller from OwinContext:

    var container = request.GetOwinContext().Get<IUnityContainer>(HttpApplicationKey.OwinPerRequestUnityContainerKey);

    5.2. Creating a controller based on this container:

    var controller = (IHttpController)container.Resolve(controllerType);
  6. Disposing a container:
    childContainer.Dispose();
  7. Completing query processing.

Result

Configure dependencies according to the required life cycles:

public static void RegisterTypes(IUnityContainer container)
{
    // ContainerControlledLifetimeManager - singleton's lifetime
    container.RegisterType<IAlwaysTheSame, AlwaysTheSame>(new ContainerControlledLifetimeManager());
    container.RegisterType<IAlwaysTheSame, AlwaysTheSame>(new ContainerControlledLifetimeManager());

    // HierarchicalLifetimeManager - container's lifetime
    container.RegisterType<ISameInARequest, SameInARequest>(new HierarchicalLifetimeManager());

    // TransientLifetimeManager (RegisterType's default) - no lifetime
    container.RegisterType<IAlwaysDifferent, AlwaysDifferent>(new TransientLifetimeManager());
}

The lifetime managers are as follows:

  1. ContainerControlledLifetimeManager creates a singleton instance in the application.
  2. HierarchicalLifetimeManager creates a singleton instance in the container.
  3. TransientLifetimeManager creates an instance each time you call the Resolve method.

The image shows GetHashCode of dependencies in the context of several HTTP requests, where:

  1. AlwaysTheSame is a singleton object in the application.
  2. SameInARequest is a singleton object in the query.
  3. AlwaysDifferent is a new instance for each Resolve method call.

You can find source codes at github.

Tags: , , Last modified: September 23, 2021
Close