Morn Morn - 9 days ago 4
C# Question

Structuremap IContainer Implementation

I am currently trying to get my head around structuremap now that the ObjectFactory static function has been marked as obsolete.

In the long run I have to use this in a MVC and WebApi application. When previously used, a line to a static method was placed in the the global.asax to initialise everything using the ObjectFactory.

ObjectFactory.Initialize{
container.For .....
}


Trying to convert this to the new IContainer approach I have come up with the following however am wondering if I have actually inadvertently implemented this often mentioned Anti-Pattern in my approach.

Static method to return container:

public class StructureMapConfig
{
public static IContainer GetContainer()
{
return new Container(container =>
{
container.For<IUserService>().Use<UserService>();
container.For<IStringService>().Use<StringService>();
container.For<IUserRepository>().Use<UserRepository>();
});
}
}


Userservice's contstructor looks like this:

public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly IStringService _stringService;

public UserService(IUserRepository userRepository, IStringService stringService)
{
_userRepository = userRepository;
_stringService = stringService;
}


Finally the initialise (this instance in a console app) looks somthing like this:

private static IUserService _userService;
private static IContainer _container;

static void Main(string[] args)
{
_container = StructureMapConfig.GetContainer();
_userService = _container.GetInstance<IUserService>();
}


So to my questions.


  1. Am I doing anything seriously wrong here

  2. In the UserService, should I be passing the IContainer in and using the object factory to get the instance or should I leave as is.

  3. Is returning the IContainer from the static method the best approach

  4. If this was a MVC app, is it best practice to build this once in the Global.asax or should the controller constructor call the static method every time.



Thanks for any advice.

Answer

To go through your questions in order:

  1. Am I doing anything seriously wrong here

No, I don't see anything seriously wrong here. There are a few improvements you could make that I'll talk about shortly.

  1. In the UserService, should I be passing the IContainer in and using the object factory to get the instance or should I leave as is.

You're correct in injecting UserService over an instance of IContainer. If your controller only requires the UserService then why inject the entire container. Really you only want to inject the bare minimum of what you need to reduce unnecessary coupling and dependencies.

  1. Is returning the IContainer from the static method the best approach

Within the removal of the ObjectFactory then yes, returning an instance of the container via a static method is a common approach for those classes whose creation is not managed via MVC's Dependency Resolution.

  1. If this was a MVC app, is it best practice to build this once in the Global.asax or should the controller constructor call the static method every time.

Creating the container in Global.asax.cs is your best approach as it's done once on Application_Start, however see below for my recommendation of using a nested container per http request.

Improvements:-

Take advantage of StructureMap's registries:

Instead of referencing the dependencies directly like this:

public static IContainer GetContainer()
{            
    return new Container(container =>
    {
        container.For<IUserService>().Use<UserService>();
        container.For<IStringService>().Use<StringService>();
        container.For<IUserRepository>().Use<UserRepository>();                
    });
}

Opt to use StructureMap's registries instead. This way you can group your dependencies (such as MVC specific dependencies or WebAPI specific dependencies, like so:

public class WebsiteRegistry : Registry
{
    public WebsiteRegistry()
    {
        this.For<IUserService>().Use<UserService>();
        this.For<IStringService>().Use<StringService>();
        this.For<IUserRepository>().Use<UserRepository>();         
    }
}

Then load your registries like this:

container.Configure(c => {
    c.IncludeRegistry<WebsiteRegistry>();
    c.IncludeRegistry<TaskRegistry>();
});

HTTP Context bound containers:

Another recommended pattern when using StructureMap with ASP.NET MVC or WebApi (or any HTTP based application) is to use nested containers that are bound to each HTTP request. This basically involves creating a new nested container on each HTTP request and then disposing it at the end of the request. This ensures that dependencies such as session objects, database connections, or UoW contexts are disposed of as soon as the HTTP request is over.

I would recommend taking a look over this article which goes into more detail on the matter and talks about how this can be set up.

This is exactly the same technique that's used in the StructureMap.MVC5 package that's often recommended by StructureMap's creator, Jeremy Miller.

Auto registering dependencies

Instead of registering every dependency with StructureMap manually you can take advantage of StructureMap's auto-registration. You can also specify your own scanning conventions.

Comments