I've a class which have a constructor like this:
private string _someString;
private ObjectA _objectA;
private ObjectB _objectB;
private Dictionary<Enum, long?> _dictionaryA;
private Dictionary<Tuple<Enum,long?>, long?> _dictionaryB;
public SomeDiClass(string someString)
{
_someString = someString;
_objectA = new ObjectA();
_objectB = new ObjectB();
_dictionaryA = new Dictionary<Enum, long?>();
_dictionaryB = new Dictionary<Tuple<Enum, long?>, long?>();
}
I want to get the dependency creation out of this constructor. In a first step I would move the ObjectA and B dependency to the constructors parameters to inject them via constructor injection. I would like to use a IoC container for this purpose, that's where I stuck at the moment. The question is what to to with someString and the dictionaries. I need to inject them to the class, because the content of the dictionaries will be an important part of unit tests. Would it be a good idea to inject the string and the dictionaries via property injection (I don't need them in other classes), so I would end up with something like this?:
private ObjectA _objectA;
private ObjectB _objectB;
public string SomeString { get; set; }
public Dictionary<Enum, long?> DictionaryA { get; set; }
public Dictionary<Tuple<Enum, long?>, long?> DictionaryB { get; set; }
public SomeDiClass(ObjectA objectA, ObjectB objectB)
{
_objectA = objectA;
_objectB = objectB;
}
Is there a best practice to solve something like this?
When should I use property injection? You should use property injection in case the dependency is truly optional, when you have a Local Default, or when your object graph contains a cyclic dependency.
Property injection is a type of dependency injection where dependencies are provided through properties. Visit the Dependency Injection chapter to learn more about it. Let's understand how we can perform property injection using Unity container. Consider the following example classes.
Setter Injection is the preferred choice when a number of dependencies to be injected is a lot more than normal, if some of those arguments are optional than using a Builder design pattern is also a good option. In Summary, both Setter Injection and Constructor Injection have their own advantages and disadvantages.
Dependency Injection is not an end goal, but a solution to a particular set of problems. For instance, Dependency Injection makes it easy to replace abstractions for unit testing and makes your application more flexible, since you can swap, decorate and intercept dependencies without having to change the consuming classes. A good introduction to Dependency Injection can be found in this freely available chapter 1 of the book Dependency Injection Principles, Practices, and Patterns (DIPP&P), which I coauthored.
That doesn't mean that you should inject every dependency a class has, since it must help you in making the class more testable and the system more maintainable. So you have to ask yourself whether it helps from a testing perspective to inject those dictionaries from the outside or if it helps to make your application more flexible. To get a good grasp on what to inject—and what not—you should learn about the concepts of Volatile and Stable Dependencies, which can be read in section 1.3 of chapter 1 of DIPP&P.
Whether it helps from a testing or maintainability perspective, is a question that is hard to answer, because your question doesn't have enough detail. But here are some pointers:
The only things you typically want to inject into a class are services and configuration values.
A service is some contract/abstraction/interface that provides 'a service.' This typically means that the service will do something on your behalf, such as calculate prices, communicate to the database, cache values, return the system's time, or format your hard drive :)
A configuration value is what it is; just a value. But you need to inject it—it can't be hard coded into the class, and you don't want the class to fetch the value itself from the ConfigurationManager
, for instance, because that would create a hidden dependency (on the Configurationmanager
) and this would make the class harder to test.
Other things, such as primitives, messages, DTOs, collection types and entities, and anything else that doesn't provide any service (business logic) and isn't in the way of unit testing, doesn't have to be abstracted and, therefore, doesn't have to be injected (and in fact shouldn't be injected through the constructor or property). In your case the dictionaries some part of the internal state of the SomeDiClass
class, not a service your class depends on.
If, on the other hand, those dictionaries are reused by other services, those dictionaries will have to be injected. But you never want to inject such dictionary itself directly, since the dictionary itself is no service. Instead you need to create an abstraction around them; something that hides the details of that dictionary and provides the application with a service around it.
You should use property injection (or setter injection) when object creation of your type is out of your control. Like aspx Page, HttpHandler, ApiController etc. For all others situations it is recommended to use constructor injection.
To resolve dependencies for aspx Page using StructureMap, i use the following approach.
First, I create a BasePage class and use StructureMap's BuildUp() method in the constructor to resolve dependencies of the derived pages. Code is given below:
public class BasePage : Page
{
public BasePage()
{
// instruct StructureMap to resolve dependencies
ObjectFactory.BuildUp(this);
}
}
public class Default : BasePage
{
public ICustomerService customerService { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
// can start using customerService
}
}
public class Login : BasePage
{
public IAuthenticationService authenticationService { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
// can start using authenticationService
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With