views:

212

answers:

3

In most samples I have seen on the web, DI in MVC Controllers is done like this

public ProductController(IProductRepository Rep)
{
    this._rep = Rep;
}

A custom ControllerFactory is used and it utilizes the DI framework of choice and the repository is injected.

Why is the above considered better than

public ProuctController()
{
    this._rep = ObjectFactory.GetInstance<IProductRepository>();
}

This will get the same results but doesn't require a custom controller factory.

As far as testing is concerned the Test App can have a separate BootStrapper. That way when the controllers are being tested they can get the fake repositories and when they are used for real they will get the real ones.

+4  A: 

When you use the second approach, disadvantages are:

  • Huge and unreadable test setup/context methods are needed
  • The container is coupled to the controller
  • You will need to write a lot more code

Why do you want to use an ioc container anyway when you don't want dependency injection?

Paco
+4  A: 

The primary drawback to the second constructor is now your IoC container has to be properly configured for each test. This setup can become a real burden as the code base grows and the test scenarios become more varied. The tests are generally easier to read and maintain when you explicitly pass in a test double.

Another concern is coupling a huge number of classes to a specific DI/IoC framework. There are ways to abstract it away, of course, but you still have code littered throughout your classes to retrieve dependencies. Since all the good frameworks can figure out what dependencies you need by looking at the constructor, it’s a lot of wasted effort and duplicated code.

OdeToCode
+3  A: 

Constructor injection (the first approach) is better than the service locator pattern (the second approach) for several reasons.

First, service locator hides dependencies. In your second example, looking at the public interface alone, there's no way to know that ProductControllers need repositories.

What's more, I've got to echo OdeToCode. I think

IProductRepository repository = Mockery.NewMock<IProductRepository>();
IProductController controller = new ProductController(repository);

is clearer than

ObjectFactory.SetFactory(IProductRepository, new MockRepositoryFactory())
IProductController controller = new ProductController();

Especially if the ObjectFactory is configured in a test fixture's SetUp method.

Finally, the service locator pattern is demonstrably sub-optimal in at least one particular case: when you're writing code that will be consumed by people writing applications outside of your control. I wager that people generally prefer constructor injection (or one of the other DI methods) because it's applicable for every scenario. Why not use the method that covers all cases?

(Martin Fowler offers a much more thorough analysis in "Inversion of Control Containers and the Dependency Injection Pattern", particularly the section "Service Locator vs Dependency Injection").

Jeff Sternal