Resolving request-scoped objects into a singleton with Autofac

This week I had an issue raised on my Github site for examples of unobtrusive validation with ASP.NET MVC. The person that raised the issue was having a problem where they wanted their fluent validation modules to be singleton, but they wanted to inject a factory that can be invoked to return a request-scoped object (in this case some sort of database store). Inevitably they came across the “No scope with a Tag matching ‘AutofacWebRequest’ is visible from the scope in which the instance was requested” error.

I’ve blogged previously about a technique for using DependencyResolver.Current and being able to unit test it for similar situations. It’s not a great solution, but it does work and at least it can be unit tested.

Low and behold though, thanks to the power of the Internet, the person that raised the issue asked a question on StackOverflow and got a really elegant solution for how to inject factories in a singleton that will correctly resolve request-scoped objects. I’m pretty excited about it so I thought I’d give it more exposure by doing this blog post.

This is the technique in all it’s glory (I’ve renamed the method name slightly to make it more readable):

public Func<T> HttpRequestScopedFactoryFor<T>()
{
    return () => DependencyResolver.Current.GetService<T>();
}

...

builder.RegisterType<SomeRequestScopedComponent>().As<ISomeRequestScopedComponent>().InstancePerHttpRequest();
builder.RegisterInstance(HttpRequestScopedFactoryFor<ISomeRequestScopedComponent>()); // this is the magic bit

This will then allow you to do something like this:

builder.RegisterType<SomeSingletonType>().As<ISomeSingletonType>().SingleInstance();

...

public class SomeSingletonType
{
    private readonly Func<ISomeRequestScopedComponent> _someRequestScopedComponentFactory;

    public SomeSingletonType(Func<ISomeRequestScopedComponent> someRequestScopedComponentFactory())
    {
        _someRequestScopedComponentFactory = someRequestScopedComponentFactory;
    }

    public void SomeMethod() {
        var requestScopedComponent = _requestScopedComponentFactory();
        ...
    }
}

Nice and even easier to unit test than using DependencyResolver.Current directly!

Big thanks to @thardy and @felix.

AutofacContrib.NSubstitute v3 release

I’d like to announce a new release for the AutofacContrib.NSubstitute library. The library was in need of a bit of love because it forced you to use a really old NSubstitute version.

I’ve made the following changes:

  • Deprecated the AutoMock class in favour of AutoSubstitute (in keeping with the theme of the NSubstitute library).
  • Added a new constructor that allows you to make modifications to the ContainerBuilder before the IContainer is built.
  • Dependency on the latest version of NSubstitute and removed the hard restriction on the NSubstitute and Autofac version numbers so the package is compatible with the latest versions of those libraries.
  • Moved the source to Github
  • Added some documentation and an example class showing some usage examples

Enjoy!

Controller instantiation testing

As I just mentioned in my post on Robust testing the best kind of test is one that automatically updates when you change your code. In particular when that test provides you a lot of value and checks something that would otherwise have a likelihood of going wrong when you deploy it (in particular production!). This post gives an example of this kind of test.

The problem

One thing that I’ve come across a number of times is a situation where controllers aren’t able to be instantiated because one of the constructor parameters isn’t able to be resolved from the dependency injection container. This is a pain and causes an ugly yellow screen of death to show up for requests to the affected controller(s) (or a nice error page if the environment you deploy to has that set up).

Ideally you should check the pages that a controller serves up after adding new parameters to it’s constructor before pushing your code changes, but sometimes you might forget and your development environment will break (I’m making a few assumptions here: continuous integration and continuous deployment to a dev environment after your tests pass). While it’s both quick and easy to identify and resolve this problem it’s annoying and can be disruptive to any testing on that environment. Ideally, the problem should be picked up much sooner than after the deployment.

Also, you may make some sort of changes that have unintended consequences like, say, changing the namespace of some classes that are registered by namespace to your dependency injection container.

In these situations, it’s impossible to use the compiler to check that the dependency resolution will work because they are resolved at run time. However, we can do the next best thing and write a test that will break!

An example solution for ASP.NET MVC

Consider the following code (this example in NUnit, but the same concept applies for other libraries):

namespace MyApp.Tests.Controllers
{
    [TestFixture]
    class ControllersShould
    {
        private IContainer _container;

        [TestFixtureSetUp]
        public void FixtureSetup()
        {
            _container = MvcApplication.RegisterDependencies();
        }

        // ReSharper disable UnusedMember.Global
        public IEnumerable<Type> GetAllControllers()
        {
            return typeof(MvcApplication).Assembly.GetTypes().Where(t => t.IsAssignableTo<ControllerBase>() && !t.IsAbstract);
        }
        // ReSharper restore UnusedMember.Global

        [Test]
        [TestCaseSource("GetAllControllers")]
        public void Instantiate(Type controller)
        {
            _container.Resolve(controller);
        }
    }
}

This test uses the (really handy) [TestCaseSource] attribute so each controller that is instantiated is presented as a separate test. This makes sense semantically and allows you to see all of the controllers that can’t be instantiated, rather than it short-circuiting at the first one that doesn’t. In saying that, if your unit testing library doesn’t support that kind of testing metadata then the same thing can be implemented as a loop inside the test.

The real magic here is in the GetAllControllers() method, which uses reflection to scan the assembly of the web application to find all classes that extend ControllerBase. You could use Controller too, but if for example you are using ActionMailer.Net then your mail controller will inherit from MailerBase, which extends ControllerBase. It also ensures the classes returned aren’t abstract.

Once you have this list of types, resolving each of them with the dependency injection container (in my case Autofac, but as with the unit testing library, this technique applies generically) you are using is easy. The only requirement is you make the method with all of your dependency registrations public and static so it’s available to call within the test. I usually have a method called RegisterDependencies() on the application class (unless the dependencies are shared with non-web projects too).

The beautiful thing about this test is that as soon as you add new controllers it will automatically apply the test to that controller! So you can literally write the test once and then forget about it :).

Note: there are a few implications of this technique that you should consider before using it:

  • This will call the constructor of all your controllers; if any of them are doing anything “funky” in their constructors then this might not be desirable. Personally, all my controller constructors ever have are storing the dependencies in the private instance scope.
  • More importantly, all of the dependencies that the controllers have and indeed all the dependencies down the chain will have their constructors called as well. This might well be a problem for your application depending on what it does so you should be very conscious of this. This usually involves me needing to set certain connection strings in the App.config of the test to test datasources etc. so the constructors don’t throw exceptions.
  • All of the dependencies to the controllers need to be such that your dependency container, with all the registrations made in your RegisterDependencies() (or similar) method, can resolve them. If you have any custom controller registration code outside of what your dependency injection framework provides you might need to adjust the approach above accordingly.
  • This is (at least in the way it’s written above, it could be adjusted though) an all-or-nothing approach – it will resolve all of the controllers.
  • If your controllers are in multiple assemblies then the GetAllControllers() method will need to be adjusted to scan the other assemblies.

Other applications

There is another application of this particular style of test that I have used before and is worth mentioning. If you are in a situation where most (or all) of your controllers must inherit from a base controller that contains important/shared functionality for your website then there is no way for you to use the compiler to check that the classes inherit that base controller. You will only find out if a new controller has that inheritance missing when loading up the site and even then, depending on the nature of the functionality, maybe only in certain circumstances (so it mightn’t be immediately obvious). As before, you can write a test that will automatically check this for you as soon as you add any new controllers.

Following is an example of such a test that I have used before:

        // ReSharper disable UnusedMember.Global
        public IEnumerable<Type> GetAllHttpControllers()
        {
            return typeof(MvcApplication).Assembly.GetTypes().Where(t => t.IsAssignableTo<Controller>() && !t.IsAbstract && t != typeof(ErrorController));
        }
        // ReSharper restore UnusedMember.Global

        [Test]
        [TestCaseSource("GetAllHttpControllers")]
        public void Inherit_from_base_controller(Type controller)
        {
            Assert.That(controller.IsAssignableTo<BaseController>());
        }

In this case the base controller class is called BaseController. There are a couple of differences to note here: I am checking for controllers that inherit from Controller rather than ControllerBase because I only want the controllers that are serving HTTP requests and I actually have an exclusion here for one particular controller, the ErrorController, because I didn’t want that particular one to extend BaseController.

Testing Url Helper within controllers in ASP.NET MVC

I recently had some code like the following in a controller that I wanted to test. The Facebook Connect API, despite being fairly awesome, is tied to the URL of the page so whenever you change the URL of your page then you will lose all your comments. This code was to get the initial URL of the page and store it in the database so that URL was used from then on:

var url = ControllerContext.RequestContext.HttpContext.Request.Url;
vm.FacebookCommentUrl = string.Format("https://{0}{1}", url.Authority, Url.Action("Detail", new { Id = "000", Controller = ArticleType.ToString() })).Replace("000", "{0}");

It’s easy to mock Request.Url within the ControllerContext; something like MVCContrib.TestHelper will mock it out for you with a few lines of code. Personally, I use the following code in conjunction with the AutoMock library to do it:

    public static class AutoMockContainer
    {
        public static AutoMock Create()
        {
            var autoMock = new AutoMock();

            var httpContext = Substitute.For<HttpContextBase>();
            autoMock.Provide(httpContext);

            var server = Substitute.For<HttpServerUtilityBase>();
            httpContext.Server.Returns(server);

            var request = Substitute.For<HttpRequestBase>();
            var parameters = new NameValueCollection();
            request.Params.Returns(parameters);
            var formParameters = new NameValueCollection();
            request.Form.Returns(formParameters);
            var qsParameters = new NameValueCollection();
            request.QueryString.Returns(qsParameters);
            var headers = new NameValueCollection();
            headers.Add("Host", "localhost");
            request.Headers.Returns(headers);
            request.AppRelativeCurrentExecutionFilePath.Returns("~/");
            request.ApplicationPath.Returns("/");
            request.Url.Returns(new Uri("http://localhost/"));
            request.Cookies.Returns(new HttpCookieCollection());
            request.ServerVariables.Returns(new NameValueCollection());
            autoMock.Provide(request);
            httpContext.Request.Returns(request);

            var response = Substitute.For<HttpResponseBase>();
            response.Cookies.Returns(new HttpCookieCollection());
            response.ApplyAppPathModifier(Arg.Any<string>()).Returns(a => a.Arg<string>());
            autoMock.Provide(response);
            httpContext.Response.Returns(response);

            var routeData = new RouteData();

            var requestContext = Substitute.For<RequestContext>();
            requestContext.RouteData = routeData;
            requestContext.HttpContext = httpContext;
            autoMock.Provide(requestContext);

            var actionExecutingContext = Substitute.For<ActionExecutingContext>();
            actionExecutingContext.HttpContext.Returns(httpContext);
            actionExecutingContext.RouteData.Returns(routeData);
            actionExecutingContext.RequestContext = requestContext;
            autoMock.Provide(actionExecutingContext);

            var actionExecutedContext = Substitute.For<ActionExecutedContext>();
            actionExecutedContext.HttpContext.Returns(httpContext);
            actionExecutedContext.RouteData.Returns(routeData);
            actionExecutedContext.RequestContext = requestContext;
            autoMock.Provide(actionExecutedContext);

            var controller = Substitute.For<ControllerBase>();
            autoMock.Provide(controller);
            actionExecutingContext.Controller.Returns(controller);

            var controllerContext = Substitute.For<ControllerContext>();
            controllerContext.HttpContext = httpContext;
            controllerContext.RouteData = routeData;
            controllerContext.RequestContext = requestContext;
            controllerContext.Controller = controller;
            autoMock.Provide(controllerContext);
            controller.ControllerContext = controllerContext;

            var iView = Substitute.For<IView>();
            autoMock.Provide(iView);

            var viewDataDictionary = new ViewDataDictionary();
            autoMock.Provide(viewDataDictionary);

            var iViewDataContainer = Substitute.For<IViewDataContainer>();
            iViewDataContainer.ViewData.Returns(viewDataDictionary);
            autoMock.Provide(iViewDataContainer);

            var textWriter = Substitute.For<TextWriter>();
            autoMock.Provide(textWriter);

            var viewContext = new ViewContext(controllerContext, iView, viewDataDictionary, new TempDataDictionary(), textWriter)
            {
                HttpContext = httpContext,
                RouteData = routeData,
                RequestContext = requestContext,
                Controller = controller
            };
            autoMock.Provide(viewContext);

            return autoMock;
        }

        public static T GetController<T>(this AutoMock autoMock) where T : Controller
        {
            var routes = new RouteCollection();
            MyApplication.RegisterRoutes(routes);
            var controller = autoMock.Resolve<T>();
            controller.ControllerContext = autoMock.Resolve<ControllerContext>();
            controller.Url = new UrlHelper(autoMock.Resolve<RequestContext>(), routes);
            return controller;
        }
    }

Above is the current version of the code that I use, but I change it every now and then when there is some other part of MVC that I need to mock, but haven’t yet. In this particular instance I was having trouble figuring out how to get Url.Action to return the actual URL – it was returning an empty string. I was registering my routes by calling the static method in my MvcApplication class, but that wasn’t enough. It took some Googling and perseverance to finally find the right set of steps to get it working (the one that really threw me was having to mock ApplyAppPathModifier in the Response object!):

  1. Register your routes in the route table
  2. Mock Request.Url (new Uri(“http://someurl/”))
  3. Mock Request.AppRelativeCurrentExecutionFilePath (“~/”)
  4. Mock Request.ApplicationPath (“/”)
  5. Mock Request.ServerVariables (new NameValueCollection())
  6. Mock Response.ApplyAppPathModifier(…) (return what is passed into it!)
  7. Set the UrlHelper in your controller to: new UrlHelper(A mock for request context with the above mocked, A route collection which has your applications routes registered into it);

Quite a strange an bizarre set of steps, but it’s what’s required to get around the core implementation within ASP.NET MVC. Maybe they will make it easier to test in the future…

With the above code snippet, I can do the following two lines of code to automatically get a controller with everything mocked correctly (not to mention any interfaces in it’s constructor automatically set to an NSubstitute Mock!):

var autoMock = AutoMockContainer.Create();
var controller = autoMock.GetController<HomeController>();

Testing code that uses Autofac + DependencyResolver in ASP.NET MVC

Sometimes it’s necessary to use DependencyResolver.Current in your MVC code where there is code that can’t be simply injected using your dependency injection framework. MVC provides a lot of extensibility points for things like model binding, model validation, and action filter, controller and view instantiation that mean that 90% of the time you can simply use your DI framework. This is made especially easy by frameworks like Autofac that provide easy MVC integration.

Use Case: Filter Provider

The main circumstance I’ve needed to use DependencyResolver.Current is in a filter provider (when trying to get precise control over globally applied filters and their execution order). I have tried passing through functors from Autofac that return the things I’m after, but you get Autofac resolution errors because it can’t tell what scope you are calling them from and if they are bound to, say, the HTTP lifetime then it can’t guarantee that the objects will be disposed correctly. There is possibly a way to inject something to correctly resolve the right Autofac lifetime scope, but I haven’t looked into it further.

An example such filter provider might be:

    public class MyAppFilterProvider : IFilterProvider
    {
        private readonly Environment _currentEnvironment;

        public MyAppFilterProvider(Environment currentEnvironment)
        {
            // Injected from Autofac
            _currentEnvironment = currentEnvironment;
        }

        public IEnumerable GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {

            // Ensure all pages other than the homepage are HTTPS in production
            if (_currentEnvironment == Environment.Prod && !(actionDescriptor.ActionName == "Index" && controllerContext.Controller.GetType() == typeof(StaticPageController)))
            {
                yield return new Filter(new RequireHttpsAttribute(), FilterScope.First, -5);
            }

            // Resolve the "current user" filter including any dependencies it may have
            // This could do something like, say put a reference to the current user from the database into the ViewBag so it can be accessed by the controller and the view
            var currentUserFilter = DependencyResolver.Current.GetService();
            yield return new Filter(currentUserFilter, FilterScope.First, -1);
        }
    }

Testing when there are calls to Dependency Resolver

Because we make use of DependencyResolver we need to be able to test it. This is trickier than it seems when using Autofac since if you resolve a service from the dependency resolver when there is no HttpContext then it will fail with “System.InvalidOperationException : The request lifetime scope cannot be created because the HttpContext is not available”. This problem may well affect other DI frameworks as well.

There are two options to combat this:

  • Create a custom class to resolve dependencies for that/those specific test/s and set it using DependencyResolver.SetResolver(new MyTestDependencyResolver()), but this could become tedious to maintain and complicates your test
  • Simulate a HTTP context by using HttpSimulator, it’s easy to install via NuGet (thanks Matt): Install-Package HttpSimulator

When testing I use an Autofac container that automatically resolves interfaces as NSubstitute Substitutes (there are similar packages for other mocking frameworks, check out Autofac.Contrib). The following code is an example of how you can set up a test:

    public class ClassThatUsesDependencyResolver
    {
        public ClassThatUsesDependencyResolver()
        {
            var service = DependencyResolver.Current.GetService();
            service.Get(1);
        }
    }

    [TestFixture]
    class DependencyResolverTests
    {
        private AutoMock _autoMock;
        private HttpSimulator _httpSimulator;

        [SetUp]
        public void Setup()
        {
            _autoMock = new AutoMock();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(_autoMock.Container));
            _httpSimulator = new HttpSimulator().SimulateRequest();
        }

        [TearDown]
        public void Teardown()
        {
            _httpSimulator.Dispose();
        }

        [Test]
        public void Test()
        {
            new ClassThatUsesDependencyResolver();
            DependencyResolver.Current.GetService().Received().Get(1);
        }
    }

One thing to note is that I used DependencyResolver.Current in the test rather than _autoMock.Resolve<…>() because the scoping that Autofac has is such that they resolve as different objects (which can be a bit confusing).

Testing the filter provider

Given I’ve shown an example filter provider above I figure I should demonstrate some of the tests that I have done in the past. There are two main things to test as far as I see (which you test for or indeed if you test for both (or don’t test it at all) depends on your situation – be pragmatic):

  • Test the order that the filters get applied is as you expect (you don’t want database calls for the current user before passive (e.g. single-sign-on) authentication is processed for instance…
  • Test that in certain circumstances a filter is applied (or not!)

An example showing both for the above filter provider is given below:

    [TestFixture]
    class MyAppFilterProviderShould
    {
        private AutoMock _autoMock;
        private HttpSimulator _httpSimulator;
        private ControllerContext _controllerContext;
        private ActionDescriptor _actionDescriptor;

        [SetUp]
        public void Setup()
        {
            _autoMock = new AutoMock();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(_autoMock.Container));
            _httpSimulator = new HttpSimulator().SimulateRequest();
            _controllerContext = Substitute.For<ControllerContext>();
            _actionDescriptor = Substitute.For<ActionDescriptor>();
        }

        [TearDown]
        public void Teardown()
        {
            _httpSimulator.Dispose();
        }

        private IEnumerable<Filter> GetFilters(Environment environment)
        {
            var filterProvider = new MyAppFilterProvider(environment);
            return filterProvider.GetFilters(_controllerContext, _actionDescriptor);
        }

        [Test]
        public void Resolve_filters_in_correct_order()
        {
            var filters = GetFilters(Environment.Prod).ToList().OrderBy(f => f.Scope).OrderBy(f => f.Order).ToList();
            var index = 0;
            Assert.That(filters[index++].Instance, Is.TypeOf<RequireHttpsAttribute>()); // Require Https should always be run first
            Assert.That(filters[index++].Instance, Is.TypeOf<CurrentUserFilter>());
            Assert.That(filters, Has.Count.EqualTo(index)); // This ensures we update the test when more filters are added
        }

        [Test]
        public void Not_require_https_when_not_in_production([Values(Environment.Dev, Environment.CI, Environment.Test)] Environment environment)
        {
            Assert.That(GetFilters(environment).Select(f => f.Instance), Has.None.TypeOf<RequireHttpsAttribute>());
        }

        [Test]
        public void Not_require_https_for_homepage_in_production()
        {
            _controllerContext.Controller = _autoMock.Resolve<StaticPageController>();
            _actionDescriptor.ActionName.Returns("Index");
            Assert.That(GetFilters(Environment.Prod).Select(f => f.Instance), Has.None.TypeOf<RequireHttpsAttribute>());
        }
    }

Update (23/03/2013)

It might not be necessary to ever use DependencyResolver.Current any more due to a new technique I’ve found.