After using Windsor Container in my applications, I am beginning to see the benefits of IOC, and how it makes like easier. The short of it all, both IOC and using a container, is that our objects should not have concrete references to other objects, and they should have their dependencies passed into them. The end goal is a loosely coupled system, whereby using contracts, our components are interchangeable, giving us more testable and portable code. Design principle two in Head First Design Patterns, "program to an interface, not an implementation." If you ask why, read this article A Conversation with Erich Gamma, Part III.
The benefits of the Windsor Container in my application are numerous. The container provides the auto-wiring of classes and their dependencies. How the container encapsulates this logic is not my concern. All I need to know is, when I register a new class instance with it, I know I can expect that component wherever that service is requested in my application. The container injects the dependency into my object, allowing me to easily swap out components that adhere to a given contract.
To see an example, I have created a service, ISiteSecurity, that will provide user and role authentication for my site. The idea behind it is that I can implement a SQL, Oracle, or file system component at my leisure. Here is my interface.
public interface ISiteSecurity{ string Source { get; set; } bool IsValid(string username, string password); bool IsInRole(string username, string role);}
My class that will implement this interface for this example is below.
public class XmlSiteSecurity : ISiteSecurity{ private string source; private XPathNavigator navigator; public XmlSiteSecurity(string Source) { this.source = Source; this.navigator = new XPathDocument(this.source).CreateNavigator(); } public string Source { get {return this.source;} set {this.source = value;} } public bool IsValid(string username, string password) { XPathNavigator nav = this.navigator.SelectSingleNode("/users/user[@username='" + username + "' and @password='" + password + "']"); if (nav != null) { return true; } return false; } public bool IsInRole(string username, string role) { XPathNavigator nav = this.navigator.SelectSingleNode("/users/user[@username='" + username + "']/roles/role[@name='" + role + "']"); if (nav != null) { return true; } return false; }}
Now let's register the service and component with Windsor Container. In my application's Application_OnStart method, I have the following.
public class MonorailApplication : HttpApplication, IContainerAccessor{ public static WindsorContainer container; public void Application_OnStart() { container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle"))); container.AddFacility("rails", new RailsFacility()); container.AddComponent("xmlsecurity", typeof(ISiteSecurity), typeof(XmlSiteSecurity)); } public IWindsorContainer Container { get { return container; } }}
Using my web.config, I set the default ISiteSecurity component with the following. To see how this is all configured, consult the Castle site for more details.
<configSections> <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" /></configSections><castle> <components> <component id="xmlsecurity"> <parameters> <Source>C:\Monorail\Website\users.config</Source> </parameters> </component> </components></castle> Now to actually leverage IOC and the Windsor Container, I have the following class. When I reference my service in my application, I request the dependency to be injected into my object's constructor. There are other ways to set this dependency, but I prefer constructor injection. The SignIn method below is used to authenticate my user in this class. When the ContentController is instantiated in my application, Windsor Container passes into it an instance of my XmlSecurity class which implements ISiteSecurity. I then validate users and do what I need. My ContentController class is ignorant of the actual instance of ISiteSecurity. public class ContentController{ ISiteSecurity security; public ContentController(ISiteSecurity Security) { this.security = Security; } public void SignIn(string username, string password) { if (security.IsValid(username, password)) { FormsAuthentication.SetAuthCookie(username, false); // redirect to some page } }} By programming to an interface, our implementations can vary, and our system becomes more flexible. Testing becomes easier. Our design is separated from our implementation. While using Windsor Container or any container for that matter is not necessary, it sure makes life simpler. Using IOC, I can rest easily knowing my objects will get the dependencies they need, regardless of whether the requirements change on me. Windsor Container makes this pretty easy. Check it out for yourself.
Now to actually leverage IOC and the Windsor Container, I have the following class. When I reference my service in my application, I request the dependency to be injected into my object's constructor. There are other ways to set this dependency, but I prefer constructor injection. The SignIn method below is used to authenticate my user in this class. When the ContentController is instantiated in my application, Windsor Container passes into it an instance of my XmlSecurity class which implements ISiteSecurity. I then validate users and do what I need. My ContentController class is ignorant of the actual instance of ISiteSecurity.
public class ContentController{ ISiteSecurity security; public ContentController(ISiteSecurity Security) { this.security = Security; } public void SignIn(string username, string password) { if (security.IsValid(username, password)) { FormsAuthentication.SetAuthCookie(username, false); // redirect to some page } }}
By programming to an interface, our implementations can vary, and our system becomes more flexible. Testing becomes easier. Our design is separated from our implementation.
While using Windsor Container or any container for that matter is not necessary, it sure makes life simpler. Using IOC, I can rest easily knowing my objects will get the dependencies they need, regardless of whether the requirements change on me. Windsor Container makes this pretty easy. Check it out for yourself.
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.
© Copyright 2009 MuellerDesigns.net
Sign In