Dependency injection, providers and ASP.NET MVC

I've been thinking a lot about all of the frameworks we have now to use with our, uh, frameworks. There's a framework to solve every problem. Dependency injection frameworks are of particular interest to a lot of people because they make unit testing ridiculously easy. They're also well suited to something like ASP.NET MVC, where you're trying to make as few dependencies as possible between the various concerns.

But I was chatting with someone the other day about all of the frameworks for DI, and he expressed concern that he wasn't comfortable depending on a lot of external libraries for some things. His view (pun intended) was that you start to junk up a relatively simple framework like MVC by putting all kinds of other stuff into it to support another framework, and that introduces different kinds of risks. For example...

  • You're decorating everything with attributes.
  • There are all kinds of configuration files or classes to do the hookup.
  • You'll replace the standard controller factories, perhaps giving new devs one more thing to learn about for your project.
  • Global.asax becomes even more of a dumping ground (more because of the placement of routing there plus DI framework init).
  • It just feels dirty to some to be using another library you don't own.

I think these are all valid concerns, though the scope of them depends a lot on your specific scenario. The funny thing about using frameworks that are named after design patterns is that everything becomes an academic debate about where and how you do this and that. And if you're a junior developer wanting to impress your peers, or a senior developer not wanting to set a precedent for the "wrong" thing, you want to get it "right."

Many of the examples published on the Web and in books suggest simply using different constructors on MVC controllers to handle DI in a rational way that doesn't require an additional framework. That allows you to keep the default controller factory and let your unit tests instantiate them with your mock objects. I read a lengthy discussion forum thread that suggested this wasn't proper either because you aren't testing the way that the objects are created in the real production environment. I thought that was a pretty thin argument, but I do see the point.

I got to thinking about how the provider model introduced in ASP.NET 2.0 worked pretty well for a lot of things, and it was used effectively before that in wiring up swappable data access layers on various apps. Creating a lightweight container to do that wire-up would be pretty straight forward, even if it did reinvent some wheels.

I don't really have a point that I'm after here. I guess these are things I'd like to hear people talk more about. What are you doing in the real world to keep things testable and maintainable?

5 Comments

  • We've gone down the path of using DI (Unity) and Service Locator (the MS version). Most of our infrastructure and domain classes have injection-friendly constructors. Our services (WCF services) have two constructors: one that is no-arg and uses Service Locator to look up its dependencies (those we wired in Unity), and another where the dependencies are taken as parameters. IN this case, the no-arg ctor forwards to the injectable constructor.

    While we're no experts, this has served us well. Everything is testable because they expose injection-friendly ctors, but for those frameworks that prefer no-arg ctors (i.e. WCF), they can still do so.

  • Sorry I beg to disagree (especially with the Provider based mindset):

    1. Not true, attribute decoration is not required most of the time, but there are certain cases it is required and I am not sure what’s wrong with that?

    2. I think most of the IoC has nice fluent syntax, which is much better than the xml version of early days. Also, most of IoC has some convention-based approach, which also reduces the number of lines of code. Does not the Provider require the config section in the web.config? Again not sure, what is wrong with this.

    3. Replacing the controller factory is just few lines of code and this is not such a thing that you are dealing with every time you are adding/modifying features, once set, no need to worry about it.

    4. No, if you know the correct pattern you can replace the whole thing with a one line of code. Maybe the following post would help you:
    http://weblogs.asp.net/rashid/archive/2009/02/17/use-bootstrapper-in-your-asp-net-mvc-application-and-reduce-code-smell.aspx

    5. What do you mean by the library that you don't own? Do you own the ASP.NET MVC or ASP.NET or .NET Framework, then why bother developing your application in this platform.

    Pls pardon me if I am being rude.

  • You aren't disagreeing with me. I was bringing up concerns I've heard from others. You don't need to convince me. If you think you're being rude, then, well, don't be rude.

    Take something like Ninject. I really dig it, but it's essentially owned by one guy. v2 is not entirely compatible with the first version. He doesn't have to support it or continue to let it live. That's a much different situation than, say, the MVC framework, which is maintained, released and supported by Microsoft. That comes with certain assurances. That was the point about "ownership."

    Alternate controller factories are configured by one line of code, yes, but the developer using it has to know what the new contract involves. As these typically use controllers with no default constructor, the way the default factory works, the developer has to know what's going on. The convention has changed.

  • Yes that is the case of using Open Source Projects maintained by certain individuals. If it is bothering you then you should start with MS Unity.

    I am not sure about the second part. Lets say if you have two controllers, like:

    public class Controller1
    {
    public Controller1(dependency1 dep1, dependency2 dep2)
    }

    And

    public class Controller2
    {
    public Controller2(dependency1 dep1, dependency2 dep2, dependency3 dep3, dependency4 dep4)
    }

    Other than expecting that these dependency will be automatically supplied by the underlying IoC what else has been changed. On a side note, if your controller requires too many dependencies, which means it doing a lot of things, time to introduce a domain service.

    I think when working with IoC it requires a different mindset, but once you get the benefits, it would be very difficult for you to write your app w/o it.

  • Unity is too... bulky. Not saying it's of poor quality or anything, only that it's total overkill for probably 90% of the things I touch.

    As many have commented on your blog at various times, there's a point at which where you're adding a lot of complexity at the expense of simplicity, and that's not always appropriate. When you start to get too dogmatic about certain patterns, it becomes a distraction for getting simple work done.

    My point is that while I understand your position, I'd summarize it as, "It's no big deal, it's easy and you should do it every time." If that's your angle, that's cool, but I'm more interested in hearing about what others are doing.

Comments have been disabled for this content.