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:

We need to create our own middleware, which will create a child 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:

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.

The main content of the GetDependencyScope method is as follows:

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:

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

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:
  3. Assigning a container in OwinContext:
  4. Using a container in other middleware:
  5. Using a container in Web API:
    5.1. Getting a controller from OwinContext:
    5.2. Creating a controller based on this container:
  6. Disposing a container:
  7. Completing query processing.

Result

Configure dependencies according to the required life cycles:

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.