Skip to content

Instantly share code, notes, and snippets.

@chrisoldwood
Created January 14, 2016 21:28
Show Gist options
  • Save chrisoldwood/0e183091d1284c99928e to your computer and use it in GitHub Desktop.
Save chrisoldwood/0e183091d1284c99928e to your computer and use it in GitHub Desktop.
A minimalist IoC container for use with ASP.Net/OWIN.
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;
namespace WebApi
{
using TypeFactories = Dictionary<Type, Func<object>>;
public sealed class SimpleDependencyResolver : IDependencyResolver
{
public SimpleDependencyResolver(TypeFactories typeFactories)
{
_typeFactories = typeFactories;
}
public void Dispose()
{
}
public IDependencyScope BeginScope()
{
return this;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return new List<object>();
}
public object GetService(Type serviceType)
{
Func<object> factory;
if (!_typeFactories.TryGetValue(serviceType, out factory))
return null;
return factory();
}
private readonly TypeFactories _typeFactories;
}
}
using System;
using System.Collections.Generic;
using System.Web.Http;
using WebApi.Controllers;
namespace WebApi
{
using TypeFactories = Dictionary<Type, Func<object>>;
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
// Web API routes...
RegisterControllers(config);
}
public static void RegisterControllers(HttpConfiguration config)
{
var messageGenerator = new MessageGenerator();
var typeFactories = new TypeFactories
{
{ typeof(TestController), () => { return new TestController(messageGenerator); } },
};
config.DependencyResolver = new SimpleDependencyResolver(typeFactories);
}
}
}
@chrisoldwood
Copy link
Author

When creating a web API with ASP.Net it can create controllers automatically, but only if they have a default constructor. However you normally need to pass some services to the controllers if they are to do anything useful, such as accessing an external resource. The only other recourse would be to enter Singleton hell.

This means that you need to provide an implementation of IDependencyResolver that can create the controller with the necessary dependencies. The implementation above (SimpleDependencyResolver.cs) allows you to do just that. The other file (WebApiConfig.cs) provides an example of how you create the type/factory map and attach the simple resolver to the HttpConfiguration object.

If the resolver seems incredibly simplistic, that's because it's supposed to be. But it's also been enough for any web API I've worked on because I assume the following:

  • Controller methods should be stateless, thread-agnostic, pure functions.
  • Dependent service calls should also be stateless and thread-agnostic where possible, e.g. database queries.
  • Resources that should be scoped, e.g. database query objects, should be explicitly scoped where they are used.

This last point implies that you don't wait until the controller gets cleaned-up to release any resources, but you do it pro-actively at the point of use, e.g. with a using statement. The sum total of all this is that you write simple, functional code that is easy to reason about because there are no hidden dependencies. It also makes unit testing simpler because you can just use basic composition techniques to allow mocks to be used instead. And because there is no reflection being used, if it compiles, the chances are it'll work :o).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment