Container Usage Guidelines

Over the years, I’ve used and abused IoC containers. While the different tools have come and gone, I’ve settled on a set of guidelines on using containers effectively. As a big fan of the Framework Design Guidelines book and its style of “DO/CONSIDER/AVOID/DON’T”, I tried to capture what has made me successful with containers over the years in a series of guidelines below.

Container configuration

Container configuration typically occurs once at the beginning of the lifecycle of an AppDomain, creating an instance of a container as the composition root of the application, and configuring and framework-specific service locators. StructureMap combines scanning for convention-based registration, and Registries for component-specific configuration.

X AVOID scanning an assembly more than once.

Scanning is somewhat expensive, as scanning involves passing each type in an assembly through each convention. A typical use of scanning is to target one or more assemblies, find all custom Registries, and apply conventions. Conventions include generics rules, matching common naming conventions (IFoo to Foo) and applying custom conventions. A typical root configuration would be:

var container = new Container(cfg =>
    cfg.Scan(scan => {

Component-specific configuration is then separated out into individual Registry objects, instead of mixed with scanning. Although it is possible to perform both scanning and component configuration in one step, separating component-specific registration in individual registries provides a better separation of conventions and configuration.

√ DO separate configuration concerning different components or concerns into different Registry classes.

Individual Registry classes contain component-specific registration. Prefer smaller, targeted Registries, organized around function, scope, component etc. All container configuration for a single 3rd-party component organized into a single Registry makes it easy to view and modify all configuration for that one component:

public class NHibernateRegistry : Registry {
    public NHibernateRegistry() {
        For<Configuration>().Singleton().Use(c => new ConfigurationFactory().CreateConfiguration());
        For<ISessionFactory>().Singleton().Use(c => c.GetInstance<Configuration>().BuildSessionFactory());
        For<ISession>().Use(c => {
            var sessionFactory = c.GetInstance<ISessionFactory>();
            var orgInterceptor = new OrganizationInterceptor(c.GetInstance<IUserContext>());
            return sessionFactory.OpenSession(orgInterceptor);

X DO NOT use the static API for configuring or resolving.

Although StructureMap exposes a static API in the ObjectFactory class, it is considered obsolete. If a static instance of a composition root is needed for 3rd-party libraries, create a static instance of the composition root Container in application code.

√ DO use the instance-based API for configuring.

Instead of using ObjectFactory.Initialize and exposing ObjectFactory.Instance, create a Container instance directly. The consuming application is responsible for determining the lifecycle/configuration timing and exposing container creation/configuration as an explicit function allows the consuming runtime to determine these (for example, in a web application vs. integration tests).

X DO NOT create a separate project solely for dependency resolution and configuration.

Container configuration belongs in applications requiring those dependencies. Avoid convoluted project reference hierarchies (i.e., a “DependencyResolution” project). Instead, organize container configuration inside the projects needing them, and defer additional project creation until multiple deployed applications need shared, common configuration.

√ DO include a Registry in each assembly that needs dependencies configured.

In the case where multiple deployed applications share a common project, include inside that project container configuration for components specific to that project. If the shared project requires convention scanning, then a single Registry local to that project should perform the scanning of itself and any dependent assemblies.

X AVOID loading assemblies by name to configure.

Scanning allows adding assemblies by name, “scan.Assembly(“MyAssembly”)”. Since assembly names can change, reference a specific type in that assembly to be registered. 

Lifecycle configuration

Most containers allow defining the lifecycle of components, and StructureMap is no exception. Lifecycles determine how StructureMap manages instances of components. By default, instances for a single request are shared. Ideally, only Singleton instances and per-request instances should be needed. There are cases where a custom lifecycle is necessary, to scope a component to a given HTTP request (HttpContext).

√ DO use the container to configure component lifecycle.

Avoid creating custom factories or builder methods for component lifecycles. Your custom factory for building a singleton component is probably broken, and lifecycles in containers have undergone extensive testing and usage over many years. Additionally, building factories solely for controlling lifecycles leaks implementation and environment concerns to services consuming lifecycle-controlled components. In the case where instantiation needs to be deferred or lifecycle needs to be explicitly managed (for example, instantiating in a using block), depending on a Func<IService> or an abstract factory is appropriate.

√ CONSIDER using child containers for per-request instances instead of HttpContext or similar scopes.

Child/nested containers inherit configuration from a root container, and many modern application frameworks include the concept of creating scopes for requests. Web API in particular creates a dependency scope for each request. Instead of using a lifecycle, individual components can be configured for an individual instance of a child container:

public IDependencyScope BeginScope() {
    IContainer child = this.Container.GetNestedContainer();
    var session = new ApiContext(child.GetInstance<IDomainEventDispatcher>());
    var resolver = new StructureMapDependencyResolver(child);
    var provider = new ServiceLocatorProvider(() => resolver);
    child.Configure(cfg =>
    return resolver;

Since components configured for a child container are transient for that container, child containers provide a mechanism to create explicit lifecycle scopes configured for that one child container instance. Common applications include creating child containers per integration test, MVVM command handler, web request etc.

√ DO dispose of child containers.

Containers contain a Dispose method, so if the underlying service locator extensions do not dispose directly, dispose of the container yourself. Containers, when disposed, will call Dispose on any non-singleton component that implements IDisposable. This will ensure that any resources potentially consumed by components are disposed properly.

Component design and naming

Much of the negativity around DI containers arises from their encapsulation of building object graphs. A large, complicated object graph is resolved with single line of code, hiding potentially dozens of disparate underlying services. Common to those new to Domain-Driven Design is the habit of creating interfaces for every small behavior, leading to overly complex designs. These design smells are easy to spot without a container, since building complex object graphs by hand is tedious. DI containers hide this pain, so it is up to the developer to recognize these design smells up front, or avoid them entirely.

X AVOID deeply nested object graphs.

Large object graphs are difficult to understand, but easy to create with DI containers. Instead of a strict top-down design, identify cross-cutting concerns and build generic abstractions around them. Procedural code is perfectly acceptable, and many design patterns and refactoring techniques exist to address complicated procedural code. The behavioral design patterns can be especially helpful, combined with refactorings dealing with long/complicated code can be especially helpful. Starting with the Transaction Script pattern keeps the number of structures low until the code exhibits enough design smells to warrant refactoring.

√ CONSIDER building generic abstractions around concepts, such as IRequestHandler<T>, IValidator<T>.

When designs do become unwieldy, breaking down components into multiple services often leads to service-itis, where a system contains numerous services but each only used in one context or execution path. Instead, behavioral patterns such as the Mediator, Command, Chain of Responsibility and Strategy are especially helpful in creating abstractions around concepts. Common concepts include:

  • Queries
  • Commands
  • Validators
  • Notifications
  • Model binders
  • Filters
  • Search providers
  • PDF document generators
  • REST document readers/writers

Each of these patterns begins with a common interface:

public interface IRequestHandler<in TRequest, out TResponse>
    where TRequest : IRequest<TResponse> {
    TResponse Handle(TRequest request);
public interface IValidator<in T> {
    ValidationResult Validate(T instance);
public interface ISearcher {
    bool IsMatch(string query);
    IEnumerable<Person> Search(string query);

Registration for these components involves adding all implementations of an interface, and code using these components request an instance based on a generic parameter or all instances in the case of the chain of responsibility pattern.

One exception to this rule is for third-party components and external, volatile dependencies.

√ CONSIDER encapsulating 3rd-party libraries behind adapters or facades.

While using a 3rd-party dependency does not necessitate building an abstraction for that component, if the component is difficult or impossible to fake/mock in a test, then it is appropriate to create a facade around that component. File system, web services, email, queues and anything else that touches the file system or network are prime targets for abstraction.

The database layer is a little more subtle, as requests to the database often need to be optimized in isolation from any other request. Switching database/ORM strategies is fairly straightforward, since most ORMs use a common language already (LINQ), but have subtle differences when it comes to optimizing calls. Large projects can switch between major ORMs with relative ease, so any abstraction would limit the use of any one ORM into the least common denominator.

X DO NOT create interfaces for every service.

Another common misconception of SOLID design is that every component deserves an interface. DI containers can resolve concrete types without an issue, so there is no technical limitation to depending directly on a concrete type. In the book Growing Object-Oriented Software, Guided by Tests, these components are referred to as Peers, and in Hexagonal Architecture terms, interfaces are reserved for Ports.

√ DO depend on concrete types when those dependencies are in the same logical layer/tier.

A side effect of depending directly on concrete types is that it becomes very difficult to over-specify tests. Interfaces are appropriate when there is truly an abstraction to a concept, but if there is no abstraction, no interface is needed.

X AVOID implementation names whose name is the implemented interface name without the “I”.

StructureMap’s default conventions do match up IFoo with Foo, and this can be a convenient default behavior, but when you have implementations whose name is the same as their interface without the “I”, that is a symptom that you are arbitrarily creating an interface for every service, when just resolving the concrete service type would be sufficient instead.  In other words, the mere ability to resolve a service type by an interface is not sufficient justification for introducing an interface.

√ DO name implementation classes based on details of the implementation (AspNetUserContext : IUserContext).

An easy way to detect excessive abstraction is when class names are directly the interface name without the prefix “I”. An implementation of an interface should describe the implementation. For concept-based interfaces, class names describe the representation of the concept (ChangeNameValidator, NameSearcher etc.) Environment/context-specific implementations are named after that context (WebApiUserContext : IUserContext).

Dynamic resolution

While most component resolution occurs at the very top level of a request (controller/presenter), there are occasions when dynamic resolution of a component is necessary. For example, model binding in MVC occurs after a controller is created, making it slightly more difficult to know at controller construction time what the model type is, unless it is assumed using the action parameters. For many extension points in MVC, it is impossible to avoid service location.

X AVOID using the container for service location directly.

Ideally, component resolution occurs once in a request, but in the cases where this is not possible, use a framework’s built-in resolution capabilities. In Web API for example, dynamically resolved dependencies should be resolved from the current dependency scope:

var validationProvider = actionContext

Web API creates a child container per request and caches this scoped container within the request message. If the framework does not provide a scoped instance, store the current container in an appropriately scoped object, such as HttpContext.Items for web requests. Occasionally, you might need to depend on a service but need to explicitly decouple or control its lifecycle. In those cases, containers support depending directly on a Func.

√ CONSIDER depending on a Func<IService> for late-bound services.

For cases where known types need to be resolved dynamically, instead of trying to build special caching/resolution services, you can instead depend on a constructor function in the form of a Func. This separates wiring of dependencies from instantiation, allowing client code to have explicit construction without depending directly on a container.

public EmailController(Func<IEmailService> emailServiceProvider) {
    _emailServiceProvider = emailServiceProvider;
public ActionResult SendEmail(string to, string subject, string body) {
    using (var emailService = _emailServiceProvider()) {
        emailService.Send(to, subject, body);

In cases where this becomes complicated, or reflection code is needed, a factory method or delegate type explicitly captures this intent.

√ DO encapsulate container usage with factory classes when invoking a container is required.

The Patterns and Practices Common Service Locator defines a delegate type representing the creation of a service locator instance:

public delegate IServiceLocator ServiceLocatorProvider();

For code needing dynamic instantiation of a service locator, configuration code creates a dependency definition for this delegate type:

public IDependencyScope BeginScope()
    IContainer child = this.Container.GetNestedContainer();
    var resolver = new StructureMapWebApiDependencyResolver(child);
    var provider = new ServiceLocatorProvider(() => resolver);
    child.Configure(cfg =>
    return new StructureMapWebApiDependencyResolver(child);

This pattern is especially useful if an outer dependency has a longer configured lifecycle (static/singleton) but you need a window of shorter lifecycles. For simple instances of reflection-based component resolution, some containers include automatic facilities for creating factories.

√ CONSIDER using auto-factory capabilities of the container, if available.

Auto-factories in StructureMap are available as a separate package, and allow you to create an interface with an automatic implementation:

public interface IPluginFactory {
    IList<IPlugin> GetPlugins();

The AutoFactories feature will dynamically create an implementation that defers to the container for instantiating the list of plugins.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Architecture, DependencyInjection. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Joe DeCock

    The color scheme of your code samples isn’t legible for me. More contrast is needed, badly. Please and thank you!

    • Vincenzo

      Same here! Reading the code is very difficult!

      • jbogard

        Not sure what happened here, we’re working on it!

      • jbogard


  • P

    Imagine that you aren’t concerned with clean component design, DDD, and the buffet of other acronyms. You have pragmatic tunnel vision. How nutty of an idea would it be to just inject Func everywhere, even when resolution doesn’t need to be dynamic?

    I’ve experienced:

    1. The “captive dependency” problem… objects with more constrained lifetime being held by objects with longer-lived lifetime.

    2. The (wasteful) big-bang object graph problem… when an MVC action only requires 1 dependency, but the dependency graph for all dependencies within the controller need to be resolved.

    3. The occasional property injection… when its 2am and I don’t feel like fixing a circular dependency issue (don’t hate).

    ServiceLocation seems to be a fix for each of these, but at the cost of giving up visibility into an object’s dependencies. Injecting Func fixes the visibility issue, albeit with some obscurity.

    I’ve wanted to give it a try to see what new problems are introduced, but I’m fearful that I’ll end up on the dailywtf. What are your thoughts?

    • jbogard

      Where does the Func come from?

      And have you seen my controllers on a diet series? I show how to get rid of bloated controllers problem.

      • P

        Yes – I did see that series (good one), and Func is provided by the container being used. Essentially the pattern for constructor injection becomes inject Func instead of injecting IFoo. As a result, if you have deep object graphs you only resolve whats needed for a specific path. If you have circular dependencies, you aren’t immediately evaluating the circular path. If you have singletons injected with request-scoped instances, the singleton isn’t holding onto an instance of the request-scoped class; its holding on to a delegate to resolve the request-scoped class. If you need to mock a dependency, you just need to add a lambda expression to provide the mock instance. Also note the need for DynamicProxy/factory/… code goes away; the Func acts as a factory.

        Outside of cleanliness and well designed components/boundaries, where do you think this approach will fall apart?

        • If your circular dependency is Foo => Bar => Foo, no Func will help you. Just avoid circular dependency from the start.

          And this approach will fall apart when you start configuring your container. No container that I know is geared to work with delegates instead of classes/interfaces.

          If you fancy functions so much, look on functional languages, like F#. Things like you describe are far easier there than in C#.

          • P

            Thanks for the response trailmax. Can we explore a few of these points further?

            re: circular dependency, I agree that these should be avoided. Just to make sure my earlier comments made sense, consider:

            If Foo depends on Func, and Bar depends on Func, you are able to satisfy the circular dependency (assuming you aren’t invoking the delegates within the constructor.. which would defeat the purpose of Func injection all together). Foo gets created with an instance of a _delegate_, meaning resolving Bar can be done later – not immediately. When Bar is eventually resolved, it gets an instance of a _delegate_ to resolve Foo, not an actual instance of Foo. Compare this to the traditional injection techniques we are used to, Foo would immediately create Bar, and Bar would immediately need Foo, which falls apart; not the case with Func injection.

            re: no container is geared toward Func injection, I just opened a console app, tried doing this with Unity and Unity works fine with ctor Func injection; no explicit registration needed. I thought this was a common feature across IoC containers?

            I remember many community posts about avoiding “ceremony”. Each time I see an explicit factory class created around a container, I have to ask.. isn’t this ceremony? Captive dependency, circular references, late-resolution, named-resolution, .. are all scenarios where I’ve seen someone explicitly create factory classes wrapping the container just to maintain the common ctor injection approach. My claim is that Func injection in the ctor can accomplish the same thing, while not sacrificing testability (if you’re into that kind of thing).

            I want to be clear that I am not suggesting that this is a better approach to injection. This is just an interesting thought exercise for me. I’m fully expecting that someone (especially those that follow Jimmy’s blog) will have an obvious technical reason why this won’t work (outside of “code smell”).

          • P

            One last note about fancying Func.. when we follow the traditional ctor injection patterns that everyone is familiar with, what is being expressed? When Foo is injected with Bar, Baz and Qux, aren’t we really saying that in order for Foo to be instantiated, Bar, Baz and Qux must also be immediately instantiated, along with each of their dependency trees? Are those semantics accurate? Going back to an earlier reply, how many times have we all seen things injected into a controller to satisfy all possible needs of all actions, when in fact, we will only be invoking a single action.

            When thinking about Func injection, aren’t we saying when Foo is instantiated, it needs the ability to resolve an instance of Bar, Baz and Qux? The dependencies of Foo are still know, and we are still inverting control, but we are doing so in a way that decouples the lifetime of the classes (there’s probably a better way to express that).

          • wow, that’s a lot to answer now. Sorry don’t have time just now, but will answer tonight, probably as a blog-post, as the discussion gets large)

          • oops. I’ve replied 2 days ago, but now my replies are gone -(
            Sorry Jimmy, did not mean to spam or anything.

          • jbogard

            I haven’t deleted anything, not sure what happened there. I only delete spam trackbacks and obvious spam comments.

  • Thanks Jimmy! Very insightful.

    Re: “X DO NOT create interfaces for every service.”

    If you don’t create interfaces for every service, then how do you unit test classes that depend on these services (i.e. when you need to mock the service)?

    Do you declare every single method and property as virtual so you can create a mock that overrides them? Dynamic Proxy? (isn’t that a lot of work vs. just having an interface?)

    • jbogard

      I don’t mock peer classes.

      • Mickaël

        Hey Jimmy,
        Great article, thanks!
        Being kind of a new user of IoC containers, I’ve fallen into service-itis and overabstraction.
        I have a hard time figuring how you don’t mock peer classes yet be able to test them. I guess they’re so small and focused you may be confident enough not to test them.
        I know you can’t show real code because of confidentiality, but do you think you can manage to create a gist with a basic example of an abstraction and a couple peer classes to show how it works?
        Thanks in advance!

    • I avoid interfaces almost entirely, if you don’t have List you have no need for an interface. Just use virtual methods. Then use an automocking container and override any methods you need to test for integration/functional tests that need an implementation of FooService.

      You almost always depend on concrete classes regardless of whether you use an interface or not. Pretty much the only real times you are not dependent on an concrete class is when you operate over something like List that has a LocalFileSystem, AzureBlobFileSystem, DatabaseFileSystem that all needs copies of your Save(obj) usage.

      • Howler

        So I understand, are you essentially saying that you should only use interfaces for network/filesystem-dependant objects, as @jbogard:disqus suggests?

        • No I’m saying you should only use interfaces for when you really have a contract that multiple consumers will need to implement. In practice I’ve seen this mostly relevant to file system access. IGenericDatabase is too generic to be usable to just swap an entire database, to use a database that generically will mean losing all of the features the database provides and only have the lowest common denominator. The file system is such a basic contract that it actually works, primarily it boils down to string filename, byte[] data, and perhaps a few other pieces of metadata like last-modified etc.

          Pretty much all other code is ridiculous to think you could reasonable replace the implementation with an entirely different implementation. The file system is one of the few dependencies that it IS very common to replace as your application grows.

      • Phil Sandler

        So mark methods virtual, even in cases where there will never be a derived type? How is that *remotely* different/better than creating an interface where there will never be a second implementation?

        You prefer making methods virtual where they don’t need to be to allow mocking, I prefer using interfaces to allow mocking. Either way you have an imperfect (or maybe useless) abstraction.

        • Yes I use virtual alot. I would disagree about marking a method virtual being a useless abstraction. It has no cost and adheres to the OCP (open-closed principle). If the method cannot be virtual that already tells you that you’re likely violating the OCP.

          Now creating an interface for the sake of mocking **is** an useless abstraction. Now you also have an entire new file to maintain. You now have 2 places to have code documented, 2 places that documented code could diverge from its xmldoc.

          • Phil Sandler

            So I would ask: are you making your methods virtual for mocking, or because you legitimately expect to inherit and override?

            It sounded like you were originally saying the former, but now you say you are doing because you don’t want to violate the OCP (“If the method cannot be virtual that already tells you that you’re likely violating the OCP.”), which leads me to conclude that you meant the latter, and that you mark everything virtual by default. If you’re doing that anyway, then it makes sense that you see that as a preferable path to mocking.

            I almost never use inheritance in the types of classes that I use in conjunction with DI–in fact I use inheritance very sparingly in general. If I see a method marked virtual, I assume it is actually intended to be overridden in a derived type. For this reason, marking methods virtual arbitrarily seems very unnatural to me, and although I acknowledge that a having a single implementation interface is imperfect, it feels “less wrong”.

            “Now you also have an entire new file to maintain.”

            I don’t see this as a great hardship. A better argument might be that now you have the interface itself to maintain, but R# makes this painless.

          • “For this reason, marking methods virtual arbitrarily seems very unnatural to me”

            The reason to mark public methods virtual is it allows the easiest variance in your system, even more so if you’re building a framework. ASP.NET has really been shifting development to this as a standard. Instead of attempting to make everything sealed or non-virtual, that they rely heavily on virtual.

            A simple example I have in a system today:
            DashFormValueProvider : NameValueCollectionValueProvider {

            public override bool ContainsPrefix(string prefix)
            return base.ContainsPrefix(GetModifiedPrefix(prefix));

            The built-in code in provides me nearly everything I need, i just need to make one minor change for my purposes.

            Going back to your mentioning of inheritance. Classical inheritance and object orientated design is a very insignificant part of modern development. I build systems targeting Service Orientated Architecture and SOA systems share many similarities to functional programming languages. OOD solves a very different set of problems unrelated to business functionality. OOD is great for variability, and not much else in practically.

            Unit (Integration) Testing is a place where variability is a key aspect.

          • Phil Sandler

            “The reason to mark public methods virtual is it allows the easiest variance in your system, even more so if you’re building a framework. ASP.NET has really been shifting development to this as a standard. Instead of attempting to make everything sealed or non-virtual, that they rely heavily on virtual.”

            Well, yes–IF you’re building a framework that is meant to be extensible. I work pretty much exclusively on internal applications (sounds like you do too).

            We agree completely on the topics of SOA, functional languages, and the role of inheritance in (non-framework) modern development. But my distaste for overuse
            of inheritance is a big part of why I find marking methods virtual unnecessarily to feel less natural. Much
            less of a problem for Java developers. :)

            There are also some practical differences between mocking an interface vs. just mocking specific methods. If you neglect to mock a specific method using the inheritance technique, you will get the behavior of the concrete type. If you use an interface you are mocking out the whole dependency, not just selective parts of it.

    • schneidr

      I’d also like to understand more about “X DO NOT create interfaces for every service”.

      I don’t see how unit testing a service that has 3 or 4 other concrete services injected is going to beneficial. Surely you are going to accidentally end up testing all the components at the same time – more of an integration test.

      Yes you can make *all* your services methods virtual, but you are just ending up with something very similar to if you had mocked an interface. If you don’t make them *all* virtual then you are having to think about what should be virtual and what shouldn’t (solely for testing purposes). Seems a strange way to design code. And again, once you are relying on concrete behavior/state and completex interactions with other objects in your unit tests …is this really unit testing?

      • jbogard

        Unit != class

        The internal structure of a unit shouldn’t matter for testing the external behavior. Mock things you can’t control (file system, web service, etc). But if I’m refactoring a class to rely on other helper classes, the original test shouldn’t change.

        I have relatively few interfaces in my systems. IUserContext, INotificationService etc. Those I stub out.

        • schneidr

          Not for external behaviour, no. But does this mean you reject all white box unit testing?

          I think a lot of people, including myself, do a large amount of white box unit testing, so I want to check sometimes that I have called a method on a dependent service. I’d rather pass in a mocked interface for that than a concrete one as tools make it very easy

          • At the the external boundary, why are you testing implementation details by checking whether the unit called some dependency? If you get the right answer…

          • Problem with checking “that I have called a method on a dependent service” that this is coupling your test with internal implementation. (Unless your mocked-out method is external service).
            If you implementation have changed (still correctly works) but does not use your initial service that you have mocked-out in test, your test will fail for a wrong reason: test expects mock to be called, but your SUT does not use that anymore.

            Once I have added a single .Include(person => person.Team) to a PsersonRepository implementation and had about 20 tests fail because they all were mocking-out IPersonRepository, but did not have a scenario for Team. That was an eye opener to stop miss-using mocks.

      • Use the mediator pattern, that way your service is interacting with a mediator, which it can use to send requests instead of calling methods on interfaces.
        When you test, if you must mock that interaction, you only have to setup the mediator with an inline delegate that confirms to the same operational contract i.e func[foroperationx, returny]

  • Rowan Freeman

    Hi Jimmy,

    “DO NOT create a separate project solely for dependency resolution and configuration.”

    The problem I have with this is that if I put my IOC framework in my (for example) MVC project, then the UI layer must reference many more libraries so that I can configure my container. This means that my UI layer “knows about” and depends on many more things; spoiling my tier/layered solution design.

    Is this a problem or am I over-thinking it? Should the UI/MVC layer know about everything so that my container can be configured, or should I only use assembly scanning so that I don’t reference anything?

    • modernNerd

      How about creating separate registration modules for each of your layers? That avoids the problem of your UI layer picking up references it needs, and allows you to move registration code to where it belongs, associated to the projects/layers that it cares about

      • Rowan Freeman

        That sounds interesting. If the registration code is elsewhere, how do I register everything if the DI is in the UI layer?

    • jbogard

      UI layer? Layers don’t reference libraries, projects reference libraries.

      Logical layers != physical layers. I have some logical layering, but almost zero physical layering, it’s a waste of time. Slices > layers.

      • Howler

        Is there any chance you can expand on this? I don’t quite get how it answers @rowanfreeman:disqus’s question…

        • Howler

          Unless you’re saying that you can fit most of the app into a one or two packages…

    • Eric Rey

      @rowanfreeman:disqus, did Jimmy ever answer this question to you?

  • acl123

    Nice comprehensive post. I largely agree with all you say, although all those DOs and DON’TS demonstrate why containers are still a bit of a nasty, complex beast.

    In regards to “building generic abstractions”, one has to be very careful. Generics can seem like fun for a while but their limitations quickly become a nightmare.

    @Rowan Freeman If your UI layer needs the dependencies to be configured then surely it needs the library to be referenced (or at least, in the bin folder)? Jimmy’s suggestion actually means you can get away with less dependencies as you don’t need to register a lot of services from unused assemblies.

    @P Most of your problems sound like your services or controllers have too many dependencies. I think giant controllers with a lot of dependencies are something to avoid – keep them small.

    • jbogard

      What limitations of generics? What’s the alternative?

      I try to keep the DI container limited in scope. A lot of what I see of complex DI is really just a smell for complex architecture, however. I try to keep in mind “what would this look like without DI”?

      • acl123

        Just off the top of my head, you need to be careful of something like this:

        void DoSomething(T animal) where T : Animal

        Looks innocuous, but observe the difference in behaviour between if I was to pass a Cat into each of the following methods:

        void MethodOne(Animal animal)

        void MethodTwo(Cat cat)

        Even if I pass the same Cat into each method, different AnimalHandlers will be used. This behaviour can be quite surprising.

        Certainly a useful technique, but you need to be careful.

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1697()

  • joomz

    All of this advice just to use an IoC container. That sums them up for me – too much complexity, magic, and risks.

    If you like IoC containers, that’s a personal choice. I’m not saying everyone should dislike them as I do.

    • jbogard

      Like or dislike has nothing to do with it – it’s a tool to solve a problem. I hear people dislike because magic/complexity, but examples of what they dislike aren’t showing bad IoC usage, but a lousy architecture to begin with.

      Granted, I only use a container when the need presents itself, not before. There are plenty of other patterns to use as well, each with their benefits and drawbacks.

      Regarding “magic”, I use a lot of “magical” tools. Compilers all the way up to Angular data-binding. What’s your definition of “magic”? You don’t know/see what’s going on behind the curtain?

    • It is only magic if you don’t understand it. Containers are a lot of reflection and many dictionaries (mostly). Nothing magical. Practice how reflection works in .Net and your magic will disappear.

  • Mike

    Would you further describe the reason behind “DO NOT use the static API for configuring or resolving.” ?

  • ardave

    Excellent series of posts here recently. Thanks!

  • Pingback: From my reading list #17 – October 13th, 2014 | Pascal Laurin()

  • TheBigSot .

    Great article,
    Could you please review “Nested Containers are not interchangeable with Child Containers.”, is confusing that you are writing about child containers, when you actually mean/use Nested container.

    Thank you