Brent Arias
Brent Arias

Reputation: 30215

Inject Using Formal Parameter Name

This question uses Unity syntax, but it applies to all IOC containers.

If I have a constructor that takes a dozen dependencies, it is no big deal:

Container.RegisterType<ICustomerService, CustomerService>();

Later I might need one of the constructor parameters to be filled by a named instance. Unfortunately the API approach now becomes very ugly:

Container.RegisterType<ICustomerService, CustomerService>(new InjectionConstructor(
    typeof(ICustomerRepository),
    typeof(IEntityMapper),
    typeof(IContext),
    typeof(IOnboardingValidator),
    typeof(ICustomerValidator),
    typeof(ICustomerVerifier), 
    typeof(ICustomerHelper), 
    new ResolvedParameter<HttpClient>("producer"), 
    typeof(ILog)));

I could avoid this kind of ugly verbosity by placing a [Dependency("producer")] annotation on the constructor parameter itself, but unfortunately then my business assembly would take a dependency on Unity libraries, which I am trying to avoid.

What would be perfect is if there was a way to tell Unity (or Autofac, Windsor, SimplerInjector, StructureMap, etcetera) to use the formal parameter name declared in the constructor "as if" it represented the named instance to inject. If the formal parameter name does not match any named binding, then it simply assumes to use the default binding.

Something like this:

Container.RegisterType<ICustomerService, CustomerService>(new InjectionNameHandler());

Perhaps this would serve the same purpose for property injection as well.

The above hypothetical directive saves me the effort of having to specify every parameter of the constructor, simply to adjust the resolution of a single parameter.

Granted this assumes that the longest constructor in the concrete type is the one I'm interested in, but that is precisely when it is most helpful!

Is there a way to do this in Unity 2? Unity 3? Or any other IOC container?

Upvotes: 2

Views: 133

Answers (1)

Steven
Steven

Reputation: 172855

If I have a constructor that takes a dozen dependencies, it is no big deal

As a matter of fact, this is a big deal. Components with many dependencies tend to violate the Single Responsibility Principle (SRP). SRP violations lead to code that is hard to test and difficult to maintain.

If you refactor your code to multiple more concise classes, the problem might not go away completely, it will already be much less of a problem.

I think your code is a great example of where you are violating the Single Responsibility Principle. The problem already starts with the name of the class: CustomerService. The 'Service' postfix already smells like a violation of the Single Responsibility Principle, Open/close Principle (OCP) and Interface Segregation Principle (ISP) to me. You are likely to violate SRP, since this class will tend to hold many use cases that are related to customers. Grouping stuff by a single entity doesn't make it a single responsibility. You will be violating OCP, because every time a new customer-related use case is added, you will have to change this class and the interface. The ICustomerService interface violates ISP, because it will have many methods, while consumers of that interface will only need one or two, but never all of them.

Besides this, the CustomerServices class depends on an ILog and ICustomerValidator services. These seem to be cross-cutting concerns and the main class should not be concerned with cross-cutting concerns. You should apply cross-cutting concerns using Aspect-Oriented Programming (AOP) techniques such as interception or (preferably) decoration.

This however inevitably will lead you to a design as described here and here, where each use case gets its own class, and all use cases are placed behind the same generic one-member-abstraction.

Later I might need one of the constructor parameters to be filled by a named instance

Although not a hard rule, my experience is that it’s not that common for a component to have both configuration values and many dependencies at the same time. So here again you might be violating the SRP here, because you might want to abstract that producer parameter away.

Especially when this HttpClient you are talking about is a .NET framework type, such as System.Net.Http.HttpClient. In that case you are violating the Dependency Inversion Principle (DIP) because not only are you depending on a concrete type instead of an abstraction, it is a framework component, but it should be your application that should define the abstractions it needs.

So instead of injecting an HttpClient, inject a service that is tailored to your application needs and follows the SOLID principles. This can never be a framework component and not even a framework supplied abstraction, because such abstraction would still violate DIP and ISP.

Upvotes: 1

Related Questions