次の方法で共有


Dependency Injection with ASP.NET Web API and Autofac

This post describes how we can use Dependency Injection (DI) in ASP.NET Web API using Autofac to accomplish a fairly common task – namely creating an ApiController with custom parameters to service an Http request.

In WebApi, we define the basic verbs of our API in a class derived from ApiController.  When an Http request is received, WebApi uses the request URL and the application’s routing tables to map the request to a specific public method in a specific ApiController class.  All parameters for that method are satisfied using normal model binding.  Those parameter values typically come from the URL or from the request body, but model binding allows them to come from almost anywhere.

But what do we do when the ApiController class itself requires parameters to be instantiated?   ApiController’s are instantiated by WebApi per request, so we can’t very well create it once and reuse it.  Moreover, there may be many running concurrently in response to multiple requests, and clearly they must not share state.  So we need a way to tell WebApi how to instantiate that ApiController using custom constructor parameters for each request.

This post shows how we do this using Autofac.

In this example, we’ll start with Phil Haack’s original TDD and Dependency Injection with ASP.NET MVC and then translate it to use Web API and Autofac

 

Getting Started

The following sample code was built using Visual Studio 2010 and the latest bits of WebApi built each night.   Henrik F. Nielsen  describes how to get the nightly AspNetWebStack bits.  Or if you prefer, you can use VS 2012 RC and get the nightly AspWebStack VS 2012 RC bits.

In either case, we’ll start by creating a new MVC 4 Web Application using File New Project.

Create

 

Create2

 

And we’ll have the basic WebApi project, ready to run.  You can F5 at this point and see a default Home page.  You can also use Fiddler to issue requests to the ValuesController to try it out.

Notice the sample ValuesController created by the template. It shows what a simple ApiController looks like, but  is too simple for our needs because it can be instantiated without any parameters.

 

Created

 

 

 

Creating the BlogController and repository

So let’s just write our new controller demonstrating what we want, and we’ll worry about wiring it up later.

In this scenario we want to expose a simple BlogController that stores references to blog posts in a separate repository.  Let’s start with an interface to the repository, which we will declare in the Models folder:

    1: namespace Autofac.Sample.Models
    2: {
    3:     public interface IPostRepository
    4:     {
    5:         void Add(Post post);
    6:         IList<Post> ListRecentPosts(int retrievalCount);
    7:     }
    8: }

 

The Post is just a data class to represent items in the repository:

    1: public class Post
    2: {
    3:     public string Author { get; set; }
    4:     public DateTime Date { get; set; }
    5:     public string Url { get; set; }
    6: }

 

And then let’s create the stub of our BlogController in the Controllers folder.  We click on the Controllers folder, and ask to Add New Controller.

newcontroller

 

which will give us this empty controller:

    1: namespace Autofac.Sample.Controllers
    2: {
    3:     public class BlogController : ApiController
    4:     {
    5:     }
    6: }

 

Let’s fill in the methods to allow us to POST new blog posts and GET existing posts:

    1: public class BlogController : ApiController
    2: {
    3:     private IPostRepository _repository;
    4:     public BlogController(IPostRepository repository)
    5:     {
    6:         _repository = repository;
    7:     }
    8:  
    9:     [HttpGet]
   10:     public IEnumerable<Post> Recent(int retrievalCount)
   11:     {
   12:         return _repository.ListRecentPosts(retrievalCount);
   13:     }
   14:  
   15:     [HttpPost]
   16:     public void Add(Post post)
   17:     {
   18:         _repository.Add(post);
   19:     }
   20: }

 

I’ve used [HttpGet] and [HttpPost] here to be explicit about the Http methods allowed and because I chose non-conventional names for the controller methods.  As mentioned before, the method parameters will be satisfied by model binding.  The Recent() method will get its retrievalCount from the URL, and the Add() method will get its Post from the request body.

But notice the important difference here – BlogController’s constructor requires an IPostRepository instance.   This means the default WebApi controller activation logic will need help to instantiate it

 

Unit testing the BlogController

Before we worry about how to wire this up, let’s write some unit tests to verify our BlogController works properly.  We’ll use https://nuget.org/packages/xunit for our unit testing framework and  https://nuget.org/packages/Moq as our mocking framework.

    1: public class BlogControllerTest
    2: {
    3:     private readonly Post _samplePost = new Post(){
    4:       Author = "Phil Haack",
    5:       Date = new DateTime(2007, 12, 7),
    6:       Url = "https://haacked.com/archive/2007/12/07/tdd-and-dependency-injection-with-asp.net-mvc.aspx"};
    7:  
    8:     [Fact]
    9:     public void Recent_Calls_Repository_ListRecentPosts()
   10:     {
   11:         // Arrange
   12:         List<Post> expectedPosts = new List<Post>() { _samplePost };
   13:         int retrievalCount = expectedPosts.Count;
   14:  
   15:         Mock<IPostRepository> repositoryMock = 
   16:            new Mock<IPostRepository>();
   17:         repositoryMock.Setup(
   18:            (m) => m.ListRecentPosts(retrievalCount))
   19:               .Returns(expectedPosts);
   20:         BlogController blogController = 
   21:            new BlogController(repositoryMock.Object);
   22:  
   23:         // Act
   24:         IEnumerable<Post> actualPosts = 
   25:           blogController.Recent(retrievalCount);
   26:  
   27:         // Assert
   28:         Assert.Equal(expectedPosts, actualPosts);
   29:     }
   30:  
   31:     [Fact]
   32:     public void Add_Calls_Repository_Add()
   33:     {
   34:         // Arrange
   35:         Post createdPost = null;
   36:  
   37:         Mock<IPostRepository> repositoryMock = 
   38:           new Mock<IPostRepository>();
   39:         repositoryMock.Setup(
   40:           (m) => m.Add(_samplePost))
   41:           .Callback<Post>(p => { createdPost = p; });
   42:  
   43:         BlogController blogController = 
   44:           new BlogController(repositoryMock.Object);
   45:  
   46:         // Act
   47:         blogController.Add(_samplePost);
   48:  
   49:         // Assert
   50:         Assert.Equal(_samplePost, createdPost);
   51:     }
   52: }

 

These two tests verify the BlogController’s Add() and Recent() methods interact correctly with the mock IPostRepository, and they are enough for what we’re trying to demonstrate here.  They show that we can simply instantiate the BlogController as we would any other object and that we can provide an IPostRepository of our choosing from the outside.

This is pretty convenient.  And it demonstrates one of the benefits of dependency injection – isolation.  We did not need to mock up an elaborate support infrastructure to instantiate our BlogController.  And the BlogController did not require other special knowledge of how to get its IPostRepository.

(Yes, I can hear the observations that current ApiControllers often do require more elaborate infrastructure to be unit tested due to additional context they typically require, such as the HttpRequestMessage, HttpConfiguration, etc.  But in this specific case, we have all we need to mock this controller’s behavior).

After we test and debug BlogController for a few cycles and decide it is working properly, we want to add it to a running application.

 

Installing Autofac

The DI framework we use in this article is https://nuget.org/packages/Autofac.  Because it is a Nuget package, it is simple to add to our application.  We do this by using Tools | Library Package Manager | Package Manager Console to bring up an interactive command window and enter “install-package autofac”, like this:

pm

 

That’s it.  Autofac is now installed into our app, and we can start using it.

 

Integrating Autofac

We could start wiring up Autofac manually but Alex Meyer-Gleaves has already done a nice integration of Autofac and WebApi at https://alexmg.com/author/Alex-Meyer-Gleaves.aspx .

If you are using the RC bits of WebApi, just install his Nuget package from https://nuget.org/packages/Autofac.WebApi and follow the instructions.

But because I am using newer WebApi bits and also want to show how the plumbing works, I chose to use copies of the sample code Alex showed in his blog post.  In this case, I extracted from https://alexmg.com/author/Alex-Meyer-Gleaves.aspx two classes: AutofacWebApiDependencyResolver and AutofacWebApiDependencyScope.  I created an Autofac folder and added these 2 classes verbatim from Alex’s post.  That way, when I eventually take a dependency on a version of Alex’s package using shipping bits, I can just remove these classes from my app.

 

af

 

Wiring up the Autofac DependencyResolver

At this point, all the moving parts are in place, and all that’s left is telling WebApi to use them.   This is done by registering an IDependencyResolver with WebApi.  The in’s and out’s of IDependencyResolver are described in greater detail in Brad Wilson’s post.  Because Alex’s AutofacWebApiDependencyResolver implements IDependencyResolver, all we need to do is instantiate it and wire it into the HttpConfiguration.   The normal place to alter the HttpConfiguration is in the App_Start\WebApiConfig class provided by the project template. 

Here is all the code we need to add to complete the wiring up of Autofac.  We’ll investigate each step separately.

 

    1: public static void Register(HttpConfiguration config)
    2: {
    3:     config.Routes.MapHttpRoute(
    4:         name: "DefaultApi",
    5:         routeTemplate: "api/{controller}/{id}",
    6:         defaults: new { id = RouteParameter.Optional }
    7:     );
    8:  
    9:     var builder = new ContainerBuilder();
   10:  
   11:     builder.RegisterInstance<IPostRepository>(new InMemoryPostRepository());
   12:  
   13:     builder.RegisterAssemblyTypes(
   14:         Assembly.GetExecutingAssembly())
   15:             .Where(t => 
   16:               !t.IsAbstract && typeof(ApiController).IsAssignableFrom(t))
   17:             .InstancePerMatchingLifetimeScope(
   18:                AutofacWebApiDependencyResolver.ApiRequestTag);
   19:  
   20:     var container = builder.Build();
   21:  
   22:     var resolver = new AutofacWebApiDependencyResolver(container);
   23:     config.DependencyResolver = resolver;
   24: }

 

At this point we’re done!   We could use F5 and start running this app.  But I think it’s worthwhile to look at these steps in more detail.

The first step was already created for us by the default WebApi template, so we leave it alone.  It sets up the basic route information to be allow our ApiControllers to be called.

    1: config.Routes.MapHttpRoute(
    2:     name: "DefaultApi",
    3:     routeTemplate: "api/{controller}/{id}",
    4:     defaults: new { id = RouteParameter.Optional });

 

The next steps do the following:

  1. Create a new Autofac container builder
  2. Scan the current assembly for all ApiController types and register them with the container builder with a per-request lifetime
  3. Ask the container builder to create the DI container
    1: var builder = new ContainerBuilder();
    2:  
    3: builder.RegisterAssemblyTypes(
    4:     Assembly.GetExecutingAssembly())
    5:         .Where(t => 
    6:            !t.IsAbstract && typeof(ApiController).IsAssignableFrom(t))
    7:         .InstancePerMatchingLifetimeScope(
    8:            AutofacWebApiDependencyResolver.ApiRequestTag);
    9:  
   10: var container = builder.Build();

Alex’s Autofac.WebApi Nuget package actually does the assembly scanning for you, but because this example does not use his bits, I do it here manually.

 

The next step wraps Alex’s IDependencyResolver around that container and registers it with WebApi:

    1: var resolver = new AutofacWebApiDependencyResolver(container);
    2: config.DependencyResolver = resolver;

 

And finally, here is the critical step that provides our IPostRepository implementation:

    1: builder.RegisterInstance<IPostRepository>(new InMemoryPostRepository());

In this case, we created an IPostRepository implementation to keep posts in memory.  We would use a database or blob store in a real application.

 

How it works

In a nutshell, it works because the Autofac DI container knows which constructors are available for BlogController, and it knows which constructor parameters can be satisfied using other instances in the DI container.

If you’re curious about the detailed steps, here they are:

  1. An Http request is received by WebApi.  Say it is something like a POST to https://localhost:43347/api/blog
  2. WebApi uses route information to understand the request is directed to the BlogController
  3. The WebApi IHttpControllerActivator extension point is called to create an instance of BlogController
  4. The default controller activator asks the registered IDependencyResolver for a new IDependencyScope (think of it as the per-request DI container).  In this case, it calls AutofacWebApiDependencyResolver.BeginScope().
  5. The default controller activator then asks the IDependencyScope for an instance of type BlogController
  6. Autofac has analyzed the BlogController and understood it has a constructor that accepts an IPostRepository
  7. Autofac also recognizes an IPostRepository instance is available from the DI container
  8. Autofac invokes the BlogController(IPostRepository) constructor, passing it the IPostRepository instance from the container.
  9. WebApi carries on with the controller instance to invoke the appropriate BlogController method – in this case the Add() method.
  10. When WebApi is done servicing the request, it disposes the IDependencyScope, thereby telling the per-request DI container it can dispose its instances.  This is how the BlogController instance is disposed.

Incidentally, the default ValuesController is also instantiated the same way.  But because it has only a parameterless constructor, that is the one used.

If you wanted to add new ApiControllers to this app that accept an IPostRepository, they would just work.  If you wanted to add new ApiControllers requiring other kinds of constructor parameters, you would just need to put instances of those parameters into the DI container as we did with the “RegisterInstance” method above.

 

Try it out

We can try out our new BlogController in action using Fiddler.  Use F5 to launch the app, wait for the Home screen to appear, and use Fiddler to POST a request like the one shown below.  This will invoke BlogController.Add() to add the post to our in-memory repository.

 

f1

 

We can then turn around and issue a GET which will call BlogController.Recent() to extract the most recent posts.

 

f2

 

 

Summary

In this article, we’ve explored how add an Autofac-based IDependencyResolver to WebApi for the express purpose of being able to create an ApiController with custom constructor parameters.  But obviously there are many ways you can use DI to build a loosely-coupled (and testable!) application.   Hopefully this article gives you some ideas where to start.

In addition to the Autofac DI container used here (https://nuget.org/packages/Autofac.WebApi) there are other DI containers available, including:

https://nuget.org/packages/Ninject.Web.WebApi

https://nuget.org/packages/Unity.WebAPI

Comments

  • Anonymous
    July 17, 2012
    Awesome,Thanks for sharing. Do you have any idea how to inject dependencies in ActionFilter ?

  • Anonymous
    August 22, 2012
    The comment has been removed

  • Anonymous
    September 14, 2012
    You can now use Autofac to create filters that support DI without using attributes. :) http://alx.to/O9n4VU

  • Anonymous
    December 17, 2012
    Hi I am using Autofac in vb.net. I could not able to find builder.RegisterAssemblyTypes method(RegisterAssemblyTypes ) & InstancePerApiRequest(). Could you please help me

  • Anonymous
    February 04, 2014
    and where is the implementation of InMemoryPostRepository ?

  • Anonymous
    June 25, 2014
    public class InMemoryPostRepository : List<Post>, IPostRepository   public IList<Post> ListRecentPosts( int retrievalCount ) {      result = new List<Post>()        for (int i = this.Count-1; i >= 0 && result.Count < retrievalCount; i--) {           result.Add( this[i] );      return result;   }   //Add provided by List<Post>

  • Anonymous
    September 30, 2014
    I really enjoy the most basic examples.  This post provides an entry point to people that have no exposure to the autofac framework.  Well done Sir!

  • Anonymous
    August 19, 2015
    builder.RegisterInstance<IPostRepository>(new InMemoryPostRepository()); are you serious? and what if InMemoryPostRepository has dependencies too?