Introduction
If you have looked around recently, you may have noticed the latest craze seems to be the poliferation of the IofC / Dependency Injection frameworks for the .Net framework. Now with the release of Enterprise Library 4.0, Microsoft has released a their own updated version that I really like, albeit I have used Enterprise Library many years now since the inception of the Data Access application block. But before I get ahead of myself, I suppose the question should be asked, "why should I use a dependancy container at all?"
Benifets of Dependency Injection
-
Don't talk to strangers! When I was learning to code this was drilled into me by my mentors. The idea is that your object should not know anything about any other object. The technical term is "loose coupling" meaning you should be able to take out one object and replace it with another object and as long as it adheres to the same interface there should not be the need for any code changes any where else in your application.
-
Configurability. It would be nice that if instead Foo, I now want to talk to FooFoo, I should be ably to just reference a new object and change the configuration to point to that new object.
-
Testabiliy. I should be able to test all functionality even if the function relys on concrete dependencies such as connection to databases or IO read/writes. With dependency injection, it is easier to do that because you can
mock those object since they are now Interfaces.
-
Another aspect that I like, especially as some who is responsible for reviewing code, is it forces you make interfaces for all you concrete classes which addresses another OO coding rule and that is you should always reference an interface and not a concreate object.
Model View Presenter Pattern and Unity
Lets get to work and create a simple application.
I will address how Model View Presenter works in another blog but basically the benifet of the pattern is its good way to separate UI from functional code not related to UI.
At any rate I have created a registration webpage, that will take the users info and pass it back several layers to a database or service layer.
10 <div>
11 New User Registration
12 <br />
13 First Name:
14 <asp:TextBox ID="txtFirstName" runat="server"></asp:TextBox><br />
15 Last Name:
16 <asp:TextBox ID="txtLastName" runat="server"></asp:TextBox><br />
17 Phone Number:
18 <asp:TextBox ID="txtPhone" runat="server"></asp:TextBox><br />
19 Email Address:
20 <asp:TextBox ID="txtEmail" runat="server"></asp:TextBox>
21 <br />
22 <asp:Button ID="Button1" runat="server" Text="Button" />
23 </div>
To use Unity first lets wire it up to Global.asax page so that when application first loads up it will get the Unity configuration and load into memory and cache it.The next step is to set up the view and the presenter. On his PNPGuidance site, David Hayden gives a really neat approach to use Generics to inject the View onto the Presenter and vice versa, so I am going to do the same thing here. The only difference is I am going to register the objects using the configuration file instead through code. David Hayden also has sample of how to do that here. With initial base work completed, I now have a view that my registation page can impliment which looks like this.
8 public interface IRegistrationView
9 {
10 string FirstName { get; }
11 string LastName { get; }
12 string Phone { get; }
13 string Email { get; }
14
15 event EventHandler RegisterClicked;
16 }
The webpage impliments this interface which I can then pass to the presenter.
26 #region IRegistrationView Members
27
28 public string FirstName
29 {
30 get { return txtFirstName.Text; }
31 }
32
33 public string LastName
34 {
35 get { return txtLastName.Text; }
36 }
37
38 public string Phone
39 {
40 get { return txtPhone.Text; }
41 }
42
43 public string Email
44 {
45 get { return txtEmail.Text; }
46 }
47
48 public event EventHandler RegisterClicked;
49
50 #endregion
51
52 protected void Button1_Click(object sender, EventArgs e)
53 {
54 if (RegisterClicked != null)
55 RegisterClicked(this, e);
56 }
The presenter handles the RegisteredClick event which I can use to pass the user down the chain via dependency injection. You can see in my presenter code that I am injecting the controller object which is the next object down the chain. It is assumed that this object would process and validate the data, applying any rules before it would then pass it to service layer.
13 IProcessUserController controller;
14
15 public RegistrationPresenter(IProcessUserController controller)
16 {
17 this.controller = controller;
18 }
19
20
21 public override void OnViewInitialized()
22 {
23 base.OnViewInitialized();
24 this.View.RegisterClicked += new EventHandler(View_RegisterClicked);
25
26 }
27
28 void View_RegisterClicked(object sender, EventArgs e)
29 {
30 User user = new User();
31 user.Email = this.View.Email;
32 user.FirstName = this.View.FirstName;
33 user.LastName = this.View.LastName;
34 user.Phone = this.View.Phone;
35 controller.RegisterUser(user);
36 }
Here is the controller code. It again injects the service/proxy class in the constructor passing the request further down the chain.
9 public class ProcessUserController : IProcessUserController
10 {
11 private readonly IUserServiceProxy proxy;
12
13
14 public ProcessUserController(IUserServiceProxy proxy)
15 {
16 //do some logic and other stuff here before passing to the service
17 this.proxy = proxy;
18 }
19
20 #region IProcessUserController Members
21
22 public void RegisterUser(UnitySamples.Core.Dto.User user)
23 {
24 proxy.InsertUser(user);
25 }
26
27 #endregion
28 }
All this magic is happening via the details of the configuration file. The controller class and the proxy class both are listed in the web.config unity section and when the configuration section is read, Unity determines where to inject what concrete class based on what interface is mapped to what class in the configuration file, and what interface is called for in the contructer of the calling class.
21 <unity>
22 <typeAliases>
23 <!-- Lifetime manager types -->
24 <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,
25 Microsoft.Practices.Unity" />
26 </typeAliases>
27 <containers>
28 <container>
29 <types>
30 <!-- Lifetime managers specified using the type aliases -->
31 <type type= "UnitySamples.Core.Controllers.IProcessUserController, UnitySamples.Core"
32 mapTo="UnitySamples.Core.Controllers.ProcessUserController, UnitySamples.Core">
33 <lifetime type="singleton" />
34 </type>
35 <type type= "UnitySamples.Core.Service.IUserServiceProxy, UnitySamples.Core"
36 mapTo="UnitySamples.Core.Service.UserServiceProxy, UnitySamples.Core">
37 <lifetime type="singleton" />
38 </type>
39 </types>
40 </container>
41 </containers>
42 </unity>