Using Unity – Part 4
- by nmarun
In this part, I’ll be discussing about constructor and property or setter injection. I’ve created a new class – Product3: 1: public class Product3 : IProduct
2: {
3: public string Name { get; set; }
4: [Dependency]
5: public IDistributor Distributor { get; set; }
6: public ILogger Logger { get; set; }
7:
8: public Product3(ILogger logger)
9: {
10: Logger = logger;
11: Name = "Product 1";
12: }
13:
14: public string WriteProductDetails()
15: {
16: StringBuilder productDetails = new StringBuilder();
17: productDetails.AppendFormat("{0}<br/>", Name);
18: productDetails.AppendFormat("{0}<br/>", Logger.WriteLog());
19: productDetails.AppendFormat("{0}<br/>", Distributor.WriteDistributorDetails());
20: return productDetails.ToString();
21: }
22: }
This version has a property of type IDistributor and takes a constructor parameter of type ILogger. The IDistributor property has a Dependency attribute (Microsoft.Practices.Unity namespace) applied to it. IDistributor and its implementation are shown below:
1: public interface IDistributor
2: {
3: string WriteDistributorDetails();
4: }
5:
6: public class Distributor : IDistributor
7: {
8: public List<string> DistributorNames = new List<string>();
9:
10: public Distributor()
11: {
12: DistributorNames.Add("Distributor1");
13: DistributorNames.Add("Distributor2");
14: DistributorNames.Add("Distributor3");
15: DistributorNames.Add("Distributor4");
16: }
17: public string WriteDistributorDetails()
18: {
19: StringBuilder distributors = new StringBuilder();
20: for (int i = 0; i < DistributorNames.Count; i++)
21: {
22: distributors.AppendFormat("{0}<br/>", DistributorNames[i]);
23: }
24: return distributors.ToString();
25: }
26: }
ILogger and the FileLogger have the following definition:
1: public interface ILogger
2: {
3: string WriteLog();
4: }
5:
6: public class FileLogger : ILogger
7: {
8: public string WriteLog()
9: {
10: return string.Format("Type: {0}", GetType());
11: }
12: }
The Unity container creates an instance of the dependent class (the Distributor class) within the scope of the target object (an instance of Product3 class that will be called by doing a Resolve<IProduct>() in the calling code) and assign this dependent object to the attributed property of the target object. To add to it, property injection is a form of optional injection of dependent objects.The dependent object instance is generated before the container returns the target object. Unlike constructor injection, you must apply the appropriate attribute in the target class to initiate property injection.
Let’s see how to change the config file to make this work. The first step is to add all the type aliases:
1: <typeAlias alias="Product3" type="ProductModel.Product3, ProductModel"/>
2: <typeAlias alias="ILogger" type="ProductModel.ILogger, ProductModel"/>
3: <typeAlias alias="FileLogger" type="ProductModel.FileLogger, ProductModel"/>
4: <typeAlias alias="IDistributor" type="ProductModel.IDistributor, ProductModel"/>
5: <typeAlias alias="Distributor" type="ProductModel.Distributor, ProductModel"/>
Now define mappings for these aliases:
1: <type type="ILogger" mapTo="FileLogger" />
2: <type type="IDistributor" mapTo="Distributor" />
Next step is to define the constructor and property injection in the config file:
1: <type type="IProduct" mapTo="Product3" name="ComplexProduct">
2: <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration">
3: <constructor>
4: <param name="logger" parameterType="ILogger" />
5: </constructor>
6: <property name="Distributor" propertyType="IDistributor">
7: <dependency />
8: </property>
9: </typeConfig>
10: </type>
There you see a constructor element that tells there’s a property named ‘logger’ that is of type ILogger. By default, the type of ILogger gets resolved to type FileLogger. There’s also a property named ‘Distributor’ which is of type IDistributor and which will get resolved to type Distributor.
On the calling side, I’ve added a new button, whose click event does the following:
1: protected void InjectionButton_Click(object sender, EventArgs e)
2: {
3: unityContainer.RegisterType<IProduct, Product3>();
4: IProduct product3 = unityContainer.Resolve<IProduct>();
5: productDetailsLabel.Text = product3.WriteProductDetails();
6: }
This renders the following output:
This completes the part for constructor and property injection. In the next blog, I’ll talk about Arrays and Generics. Please see the code used here.