From: <jer...@us...> - 2009-01-05 04:28:02
|
Revision: 216 http://structuremap.svn.sourceforge.net/structuremap/?rev=216&view=rev Author: jeremydmiller Date: 2009-01-05 04:27:51 +0000 (Mon, 05 Jan 2009) Log Message: ----------- more documentation Modified Paths: -------------- trunk/Source/HTML/AutoWiring.htm trunk/Source/HTML/ChangingConfigurationAtRuntime.htm trunk/Source/HTML/Concepts.htm trunk/Source/HTML/ConfiguringStructureMap.htm trunk/Source/HTML/Default.htm trunk/Source/HTML/Generics.htm trunk/Source/HTML/Glossary.htm trunk/Source/HTML/HTML.csproj trunk/Source/HTML/InstanceExpression.htm trunk/Source/HTML/Menu.htm trunk/Source/HTML/NodeNormalized.htm trunk/Source/HTML/RegistryDSL.htm trunk/Source/HTML/RetrievingServices.htm trunk/Source/HTML/ScanningAssemblies.htm trunk/Source/HTML/UsingSessionContext.htm trunk/Source/HTML/style.css Added Paths: ----------- trunk/Source/HTML/DependencyInjection.htm trunk/Source/HTML/InversionOfControl.htm Modified: trunk/Source/HTML/AutoWiring.htm =================================================================== --- trunk/Source/HTML/AutoWiring.htm 2009-01-04 02:55:42 UTC (rev 215) +++ trunk/Source/HTML/AutoWiring.htm 2009-01-05 04:27:51 UTC (rev 216) @@ -82,7 +82,9 @@ <h2> Example</h2> <p> - Typically, you’ll try to minimize the number of service locator[LINK] usages in + Typically, you’ll try to minimize the number of + <a href="%20%20%20%20%20%20%20%20%20%20%20%20Typically,%20you’ll%20try%20to%20minimize%20the%20number%20of%20Service%20Locator%20usages%20in%20">Service Locator</a> + (Container.Get*****) usages in your system to a bare minimum (I found 8 in my current system, but I think I’ll find a way to prune half of those later). Most of the value of an IoC tool is in automatically doing Dependency Injection. I’m working with the new Modified: trunk/Source/HTML/ChangingConfigurationAtRuntime.htm =================================================================== --- trunk/Source/HTML/ChangingConfigurationAtRuntime.htm 2009-01-04 02:55:42 UTC (rev 215) +++ trunk/Source/HTML/ChangingConfigurationAtRuntime.htm 2009-01-05 04:27:51 UTC (rev 216) @@ -259,8 +259,8 @@ functionality in favor of the simple ObjectFactory/Container.Inject<T>(T object) methods.</p> <p>My strong advice is to not use the Container or ObjectFactory in unit tests in - the mass majority of cases. Rather, my advice is to use simple Dependency - Injection[LINK] to inject mock objects during unit tests. However, there + the mass majority of cases. Rather, my advice is to use simple + <a href="DependencyInjection.htm">Dependency Injection</a> to inject mock objects during unit tests. However, there are still times when you want or need a class to use the Container or ObjectFactory itself to get dependencies at runtime. For that case, here is a sample:</p> Modified: trunk/Source/HTML/Concepts.htm =================================================================== --- trunk/Source/HTML/Concepts.htm 2009-01-04 02:55:42 UTC (rev 215) +++ trunk/Source/HTML/Concepts.htm 2009-01-05 04:27:51 UTC (rev 216) @@ -1,9 +1,438 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> - <title></title> + <title>Software Design Concepts</title> + <link rel="stylesheet" type="text/css" href="style.css" /> + <script type="text/javascript" src="jquery-1.2.6.js"></script> + <script type="text/javascript" src="structuremap.js"></script> </head> <body> + <p> + Before you jump into using StructueMap in anger, there are some design concepts + that can help you get the most out of an IoC tool. This web page is + strictly about conceptual design fundamentals, and not particularly specific to + StructureMap itself. I think this stuff is important to real world + development. You might not memorize the "Liskov Substitution Principle" + text, but you're code will be better for following its intent -- even if you + don't particulary know the exact term for LSP. When you read this section, + please focus on the concepts and any class's role within a system rather than + get caught up in coding details like "why is he using an AddressController + instead of that being part of another class?"</p> + <p> + </p> + <h2> + Design Concepts</h2> + <p> + Over the years a series of concepts and principles have been discovered and + developed to describe well-structured Object Oriented systems. To most + effectively use StructureMap, or any other IoC tool for that matter, your system + needs to be designed with these principles first: + </p> + <ul> + <li><a href="http://en.wikipedia.org/wiki/Separation_of_concerns" + mce_href="http://en.wikipedia.org/wiki/Separation_of_concerns">Separation of + Concerns</li> + <li><a href="http://msdn.microsoft.com/en-us/magazine/cc546578.aspx" + mce_href="http://msdn.microsoft.com/en-us/magazine/cc546578.aspx">Open + Closed Principle, the Single Responsibility Principle, and the Liskov + Substitution Principle</a></li> + <li><a href="http://codebetter.com/blogs/jeremy.miller/pages/129542.aspx" + mce_href="http://codebetter.com/blogs/jeremy.miller/pages/129542.aspx"> + Responsibilities, Cohesion, and Coupling</a></li> + <li><a href="http://codebetter.com/blogs/jeremy.miller/archive/2007/01/08/Orthogonal-Code.aspx" + mce_href="http://codebetter.com/blogs/jeremy.miller/archive/2007/01/08/Orthogonal-Code.aspx"> + Orthogonal Code</a></li> + <li><a href="http://codebetter.com/blogs/jeremy.miller/pages/129543.aspx" + mce_href="http://codebetter.com/blogs/jeremy.miller/pages/129543.aspx"> + Dependency Inversion Principle</a></li> + <li><a href="http://www.artima.com/lejava/articles/designprinciples4.html" + mce_href="http://www.artima.com/lejava/articles/designprinciples4.html"> + Favor Composition over Inheritance</a></li> + </ul> + <p> + To sum it all up, well designed Object Oriented systems are <b>composed</b> of + many objects that work with each other to accomplish to goals of the system. + We want our systems to be decomposed into cohesive classes that perform a well + defined responsibility within the system, rather than monolithic “God” classes + that do too much. A cohesive class will have to be dependent upon other + classes to perform services outside of its own tightly defined responsibility. + In IoC speak, we call the collaborating objects <b>dependencies</b>. + </p> + <hr /> + <h2 class="style1"> + Dependencies</h2> + <p> + For example, in my current system we have a class called + <font face="Courier New">AddressEditController</font> that governs the creation + and editing of Address entities in our web based UI. The + AddressEditController needs to validate user input and persist or load data. + Those are two distinct responsibilities, so AddressEditController has + dependencies on other objects for these services. + </p> + <div style="border: thin solid black; background: white none repeat scroll 0% 50%; font-size: 10pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: courier new;"> + <p style="margin: 0px;"> + <span style="color: blue;">public</span> <span style="color: blue;">class</span> + <span style="color: rgb(43, 145, 175);">AddressEditController</span> : + <span style="color: rgb(43, 145, 175);">Controller</span></p> + <p style="margin: 0px;"> + {</p> + <p style="margin: 0px;"> + <span style="color: green;">// AddressEditController + uses IValidator to validate user input</span></p> + <p style="margin: 0px;"> + <span style="color: green;">// and IRepository to + load and save Address information</span></p> + <p style="margin: 0px;"> + <span style="color: blue;">private</span> + <span style="color: blue;">readonly</span> + <span style="color: rgb(43, 145, 175);">IValidator</span> _validator;</p> + <p style="margin: 0px;"> + <span style="color: blue;">private</span> + <span style="color: rgb(43, 145, 175);">IRepository</span> _repository;</p> + <p style="margin: 0px;"> + </p> + <p style="margin: 0px;"> + }</p> + </div> + <p> + So here’s some facts about <font face="Courier New">AddressEditController:</font></p> + <ul> + <li><font face="Courier New">AddressEditController</font> depends on + <font face="Courier New">IValidator</font> and <font face="Courier New"> + IRepository</font> </li> + <li><font face="Courier New">AddressEditController</font> cannot function unless it + has both an <font face="Courier New">IValidator</font> and an + <font face="Courier New">IRepository</font></li> + <li>From the concepts section above, for best results, the <font face="Courier New"> + AddressEditController</font> should be loosely coupled to its dependencies by + knowing as little about the inner workings of the real <font face="Courier New"> + IValidator</font> and <font face="Courier New">IRepository</font></li> + <li>The real IRepository is a Gateway into NHibernate. The concrete Repository class + cannot be used without its own dependency trail of external configuration, a + Singleton to keep track of an expensive resource, and some NHibernate + bootstrapping code. </li> + </ul> + <p> + Just calling a new() constructor on its dependencies isn’t the best design for + our <font face="Courier New">AddressEditController</font>. Creating a + concrete Validator class is very possible, but what if we want to selectively + replace the implementation of IValidator later? That’s only somewhat + likely, but the dependency on Repository is a much larger concern. I might + have semantic decoupling between <font face="Courier New">AddressEditController</font> + and Repository, but if <font face="Courier New">AddressEditController</font> + calls new Repository() itself, <font face="Courier New">AddressEditController</font> + will not be able to function without all that NHibernate bootstrapping. I + do not want a piece of my user interface to be tightly coupled to the existence + of the persistence layer. + </p> + <p> + In other scenarios, creating the dependencies may involve more than just calling + new() on the dependencies (don’t believe me? Go try to create an + HttpContext object).</p> + <p> + <font face="Courier New">AddressEditController</font> is responsible for the + workflow around editing Address entities in the UI. It shouldn’t be + concerned with NHibernate configuration and whatnot. One way to solve this + problem is to move the responsibility for building its dependencies to somewhere + external to <font face="Courier New">AddressEditController</font>. + </p> + <hr /> + <h2> + Inversion of Control and Dependency Injection</h2> + <p> + In many cases, I don’t want my classes to have to be aware of how their + dependencies are created or located. I don’t want controller classes to + even care that they’re using an object that is created via Microsoft’s Provider + infrastructure, or a Singleton, or needs configuration data. My class + should only know the public interfaces of its dependencies. I can make + that true by applying “<a + href="http://codebetter.com/blogs/jeremy.miller/archive/2005/09/20/132290.aspx" + mce_href="http://codebetter.com/blogs/jeremy.miller/archive/2005/09/20/132290.aspx">Inversion + of Control</a>.” Instead of doing:</p> + <div style="border: thin solid black; background: white none repeat scroll 0% 50%; font-size: 10pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: courier new;"> + <p style="margin: 0px;"> + <span style="color: blue;">public</span> + AddressEditController()</p> + <p style="margin: 0px;"> + {</p> + <p style="margin: 0px;"> + _validator = + <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);"> + Validator</span>();</p> + <p style="margin: 0px;"> + _repository = + <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);"> + Repository</span>();</p> + <p style="margin: 0px;"> + }</p> + </div> + <p> + where <font face="Courier New">AddressEditController</font> calls linearly + through to the constructors on Validator and Repository, we can invert the + control to make the creator of <font face="Courier New">AddressEditController</font> + responsible for building the dependencies and “pushing” them into + <font face="Courier New">AddressEditController</font>. + </p> + <div style="border: thin solid black; background: white none repeat scroll 0% 50%; font-size: 10pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: courier new;"> + <p style="margin: 0px;"> + <span style="color: blue;">public</span> <span style="color: blue;">class</span> + <span style="color: rgb(43, 145, 175);">AddressEditController</span> : + <span style="color: rgb(43, 145, 175);">Controller</span></p> + <p style="margin: 0px;"> + {</p> + <p style="margin: 0px;"> + </p> + <p style="margin: 0px;"> + </p> + <span style="color: blue;">private</span> <span style="color: blue;"> + readonly</span> <span style="color: rgb(43, 145, 175);">IValidator</span> + _validator; + <p style="margin: 0px;"> + <span style="color: blue;">private</span> + <span style="color: rgb(43, 145, 175);">IRepository</span> _repository;</p> + <p style="margin: 0px;"> + </p> + <p style="margin: 0px;"> + <span style="color: blue;">public</span> + AddressEditController(<span style="color: rgb(43, 145, 175);">IValidator</span> + validator, <span style="color: rgb(43, 145, 175);">IRepository</span> + repository)</p> + <p style="margin: 0px;"> + {</p> + <p style="margin: 0px;"> + _validator = validator;</p> + <p style="margin: 0px;"> + _repository = repository;</p> + <p style="margin: 0px;"> + }</p> + <p style="margin: 0px;"> + }</p> + </div> + <p> + The code sample above uses a form of Inversion of Control called + <a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/10/06/132825.aspx" + mce_href="http://codebetter.com/blogs/jeremy.miller/archive/2005/10/06/132825.aspx"> + Dependency Injection</a> to push in the dependencies via a constructor function. + Of course, at some point, something needs to know how to create the entire chain + of dependencies and do all of that Dependency Injection. StructureMap + supports a pattern known as + <a href="http://martinfowler.com/articles/injection.html#UsingAServiceLocator" + mce_href="http://martinfowler.com/articles/injection.html#UsingAServiceLocator"> + Service Locator</a>:</p> + <div style="border: thin solid black; background: white none repeat scroll 0% 50%; font-size: 10pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: courier new;"> + <p style="margin: 0px;"> + <span style="color: green;"> + // Creates an AddressEditController with all of its dependencies</span></p> + <p style="margin: 0px;"> + + <span style="color: rgb(43, 145, 175);">AddressEditController</span> controller + = <span style="color: rgb(43, 145, 175);">ObjectFactory</span>.GetInstance<<span + style="color: rgb(43, 145, 175);">AddressEditController</span>>();</p> + </div> + <p> + <font face="Courier New">ObjectFactory</font> is a StructureMap class that + serves as a well known place to go and find any service that you need. + When the <font face="Courier New">AddressEditController</font> is created and + returned by <font face="Courier New">ObjectFactory</font>, it should be + completely ready to go. There’s another important concept to understand + before you use StructureMap. + </p> + <hr /> + <h2> + Auto Wiring</h2> + <p> + Every "real" IoC container supports the concept of "Auto Wiring." Auto + Wiring simply means that StructureMap can figure out dependency chains for you + without a lot of explicit configuration. When you ask for + <font face="Courier New">AddressEditController</font>, there is more going on + than just <font face="Courier New">AddressEditController</font> and its two + dependencies. The Repository class itself has its own dependencies.</p> + <div style="border: thin solid black; background: white none repeat scroll 0% 50%; font-size: 10pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: courier new;"> + <p style="margin: 0px;"> + [<span style="color: rgb(43, 145, 175);">DefaultConstructor</span>]</p> + <p style="margin: 0px;"> + <span style="color: blue;">public</span> Repository(<span + style="color: rgb(43, 145, 175);">ISessionSource</span> source) : + <span style="color: blue;">this</span>(source.CreateSession())</p> + <p style="margin: 0px;"> + {</p> + <p style="margin: 0px;"> + </p> + <p style="margin: 0px;"> + }</p> + </div> + <p> + In turn, the concrete version of <font face="Courier New">ISessionSource</font> + above has <b>its</b> own dependencies:</p> + <div style="border: thin solid black; background: white none repeat scroll 0% 50%; font-size: 10pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: courier new;"> + <p style="margin: 0px;"> + <span style="color: blue;">public</span> + SessionSource(<span style="color: rgb(43, 145, 175);">IDictionary</span><<span + style="color: blue;">string</span>, <span style="color: blue;">string</span>> + properties, <span style="color: rgb(43, 145, 175);">PersistenceModel</span> + model)</p> + <p style="margin: 0px;"> + {</p> + <p style="margin: 0px;"> + _configuration = + <span style="color: blue;">new</span> <span style="color: rgb(43, 145, 175);"> + Configuration</span>();</p> + <p style="margin: 0px;"> + + _configuration.AddProperties(properties);</p> + <p style="margin: 0px;"> + </p> + <p style="margin: 0px;"> + + model.Configure(_configuration);</p> + <p style="margin: 0px;"> + </p> + <p style="margin: 0px;"> + _sessionFactory = + _configuration.BuildSessionFactory();</p> + <p style="margin: 0px;"> + }</p> + </div> + <p> + which starts to get interesting because <font face="Courier New">SessionSource</font> + needs some information like connection strings that have to come in from Xml + configuration: + </p> + <div style="border: thin solid black; background: white none repeat scroll 0% 50%; font-size: 10pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: courier new;"> + <p style="margin: 0px;"> + <span style="color: blue;"><</span><span style="color: rgb(163, 21, 21);">StructureMap</span><span + style="color: blue;"> </span><span style="color: red;">MementoStyle</span><span + style="color: blue;">=</span>"<span style="color: blue;">Attribute</span>"<span + style="color: blue;">></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> <</span><span + style="color: rgb(163, 21, 21);">DefaultInstance</span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> </span><span style="color: red;"> + PluginType</span><span style="color: blue;">=</span>"<span style="color: blue;">ShadeTree.DomainModel.ISessionSource,ShadeTree.DomainModel</span>"</p> + <p style="margin: 0px;"> + <span style="color: blue;"> </span><span style="color: red;"> + PluggedType</span><span style="color: blue;">=</span>"<span + style="color: blue;">ShadeTree.DomainModel.SessionSource,ShadeTree.DomainModel</span>"<span + style="color: blue;">></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> <</span><span + style="color: rgb(163, 21, 21);">properties</span><span + style="color: blue;">></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> <</span><span + style="color: rgb(163, 21, 21);">Pair</span><span style="color: blue;"> + </span><span style="color: red;">Key</span><span style="color: blue;">=</span>"<span + style="color: blue;">connection.provider</span>"<span style="color: blue;"> + </span><span style="color: red;">Value</span><span style="color: blue;">=</span>"<span + style="color: blue;">NHibernate.Connection.DriverConnectionProvider</span>"<span + style="color: blue;"> /></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> <</span><span + style="color: rgb(163, 21, 21);">Pair</span><span style="color: blue;"> + </span><span style="color: red;">Key</span><span style="color: blue;">=</span>"<span + style="color: blue;">connection.driver_class</span>"<span + style="color: blue;"> </span><span style="color: red;">Value</span><span + style="color: blue;">=</span>"<span style="color: blue;">NHibernate.Driver.SqlClientDriver</span>"<span + style="color: blue;"> /></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> <</span><span + style="color: rgb(163, 21, 21);">Pair</span><span style="color: blue;"> + </span><span style="color: red;">Key</span><span style="color: blue;">=</span>"<span + style="color: blue;">dialect</span>"<span style="color: blue;"> </span> + <span style="color: red;">Value</span><span style="color: blue;">=</span>"<span + style="color: blue;">NHibernate.Dialect.MsSql2000Dialect</span>"<span + style="color: blue;"> /></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> <</span><span + style="color: rgb(163, 21, 21);">Pair</span><span style="color: blue;"> + </span><span style="color: red;">Key</span><span style="color: blue;">=</span>"<span + style="color: blue;">hibernate.dialect</span>"<span style="color: blue;"> + </span><span style="color: red;">Value</span><span style="color: blue;">=</span>"<span + style="color: blue;">NHibernate.Dialect.MsSql2000Dialect</span>"<span + style="color: blue;"> /></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> <</span><span + style="color: rgb(163, 21, 21);">Pair</span><span style="color: blue;"> + </span><span style="color: red;">Key</span><span style="color: blue;">=</span>"<span + style="color: blue;">use_outer_join</span>"<span style="color: blue;"> + </span><span style="color: red;">Value</span><span style="color: blue;">=</span>"<span + style="color: blue;">true</span>"<span style="color: blue;"> /></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> <</span><span + style="color: rgb(163, 21, 21);">Pair</span><span style="color: blue;"> + </span><span style="color: red;">Key</span><span style="color: blue;">=</span>"<span + style="color: blue;">connection.connection_string</span>"<span + style="color: blue;"> </span><span style="color: red;">Value</span><span + style="color: blue;">=</span>"<span style="color: blue;">a connection string + that I’m certainly not giving out to you!</span>"<span style="color: blue;"> /></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> <</span><span + style="color: rgb(163, 21, 21);">Pair</span><span style="color: blue;"> + </span><span style="color: red;">Key</span><span style="color: blue;">=</span>"<span + style="color: blue;">show_sql</span>"<span style="color: blue;"> </span> + <span style="color: red;">Value</span><span style="color: blue;">=</span>"<span + style="color: blue;">true</span>"<span style="color: blue;"> /></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> </</span><span + style="color: rgb(163, 21, 21);">properties</span><span + style="color: blue;">></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"> </</span><span + style="color: rgb(163, 21, 21);">DefaultInstance</span><span + style="color: blue;">></span></p> + <p style="margin: 0px;"> + <span style="color: blue;"></</span><span style="color: rgb(163, 21, 21);">StructureMap</span><span + style="color: blue;">></span></p> + </div> + <p> + Here’s some of the configuration for the other services that the entire + EditAddressController needs:</p> + <div style="border: thin solid black; background: white none repeat scroll 0% 50%; font-size: 10pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: courier new;"> + <p style="margin: 0px;"> + ForRequestedType<<span + style="color: rgb(43, 145, 175);">IValidator</span>>().TheDefaultIsConcreteType<<span + style="color: rgb(43, 145, 175);">Validator</span>>();</p> + <p style="margin: 0px;"> + ForRequestedType<<span + style="color: rgb(43, 145, 175);">IRepository</span>>().TheDefaultIsConcreteType<<span + style="color: rgb(43, 145, 175);">Repository</span>>().CacheBy(<span + style="color: rgb(43, 145, 175);">InstanceScope</span>.Hybrid);</p> + <p style="margin: 0px;"> + ForRequestedType<<span + style="color: rgb(43, 145, 175);">PersistenceModel</span>>().TheDefaultIsConcreteType<<span + style="color: rgb(43, 145, 175);">DovetailPersistenceModel</span>>();</p> + </div> + <p> + At no point did I specify that <font face="Courier New">EditAddressController</font> + needs an <font face="Courier New">IRepository</font> that needs an + <font face="Courier New">ISessionSource</font> that needs 2-3 other things, but + yet when I call:</p> + <div style="border: thin solid black; background: white none repeat scroll 0% 50%; font-size: 10pt; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: black; font-family: courier new;"> + <p style="margin: 0px;"> + <span style="color: green;"> + // Creates an AddressEditController with all of its dependencies</span></p> + <p style="margin: 0px;"> + + <span style="color: rgb(43, 145, 175);">AddressEditController</span> controller + = <span style="color: rgb(43, 145, 175);">ObjectFactory</span>.GetInstance<<span + style="color: rgb(43, 145, 175);">AddressEditController</span>>();</p> + </div> + <p> + StructureMap will construct <font face="Courier New">EditAddressController</font> + that had a new instance of <font face="Courier New">Repository</font> that had a + new instance of <font face="Courier New">SessionSource</font> that had an + <font face="Courier New">IDictionary<string, string></font> object and a new + instance of <font face="Courier New">DovetailPersistenceModel</font>. I + don’t have to explicitly tell StructureMap to do that for me because it uses its + “Auto Wiring” feature to examine the dependencies of each concrete class and act + accordingly. StructureMap does need to know what to do with each type of + object it encounters. When it tries to build the <font face="Courier New"> + Repository</font> class StructureMap sees the constructor argument for + <font face="Courier New">ISessionSource</font> on <font face="Courier New"> + Repository</font>, and knows to build and inject a new <font face="Courier New"> + SessionSource</font> object (and so on as deep as you need to go).</p> + </body> </html> \ No newline at end of file Modified: trunk/Source/HTML/ConfiguringStructureMap.htm =================================================================== --- trunk/Source/HTML/ConfiguringStructureMap.htm 2009-01-04 02:55:42 UTC (rev 215) +++ trunk/Source/HTML/ConfiguringStructureMap.htm 2009-01-05 04:27:51 UTC (rev 216) @@ -15,7 +15,8 @@ else from the initial releases to StructureMap 2.5+. You have three forms of configuration to choose from:</p> <ol> - <li><a href="RegistryDSL.htm">Registry DSL</a> -- The programmatic Fluent Interface[LINK] API for configuring the Container in code.</li> + <li><a href="RegistryDSL.htm">Registry DSL</a> -- The programmatic + <a href="http://www.martinfowler.com/bliki/FluentInterface.html">Fluent Interface</a> API for configuring the Container in code.</li> <li><a href="XmlConfiguration.htm">Xml configuration</a> (StructureMap.config, the App.config file, or named files)</li> <li><a href="UsingAttributes.htm">StructureMap Attributes </a>-- Not fully deprecated, but not really recommended either. </li> </ol> Modified: trunk/Source/HTML/Default.htm =================================================================== --- trunk/Source/HTML/Default.htm 2009-01-04 02:55:42 UTC (rev 215) +++ trunk/Source/HTML/Default.htm 2009-01-05 04:27:51 UTC (rev 216) @@ -10,7 +10,7 @@ <p> StructureMap is a <a href="http://www.martinfowler.com/articles/injection.html">Dependency - Injection</a> / Inversion of Control[LINK] tool for .Net that can be used to improve the architectural + Injection</a> / <a href="InversionOfControl.htm">Inversion of Control</a> tool for .Net that can be used to improve the architectural qualities of an object oriented system by reducing the mechanical costs of good design techniques. StructureMap can enable looser coupling between classes and their dependencies, improve the testability of a class structure, and provide @@ -40,25 +40,30 @@ <p>Do not use StructureMap if an application or process requires little flexibility. The abstraction and indirection afforded by StructureMap is unnecessary and even harmful in simpler systems or processes. </p> - <h3>Status</h3> + <p>The easiest way to get started is with the <a href="QuickStart.htm">StructureMap + QuickStart</a>. Please send any questions or suggestions to the + <a href="http://groups.google.com/group/structuremap-users/post?hl=en"> + StructureMap User Group</a> on Google Groups.</p> + <p> </p> + <h2>Status</h2> <p>StructureMap is the oldest IoC/DI tool for .Net development and has been used in multiple production systems since June 2004. The current version 2.5.2 was released in January 2009, with a - 2.6 release scheduled no later than the end of January 2009. StructureMap is + 2.6 release scheduled for no later than the end of January 2009. StructureMap is primarily maintained and developed by <a href="mailto:jer...@ya...?subject=StructureMap">Jeremy D. Miller</a>, <a href="http://codebetter.com/blogs/jeremy.miller">The - Shade Tree Developer</a> and Joshua Flanagan [LINK] with other contributions from + Shade Tree Developer</a> and + <a href="http://www.lostechies.com/blogs/joshuaflanagan/default.aspx">Joshua Flanagan</a> with other contributions from the community.</p> <hr /> - <h2> - <strong>Related Links:</strong></h2> + <h2>Related Links:</h2> <ul> <li><a href="http://flimflan.com/blog/HelloStructureMap.aspx">Hello StructureMap</a> </li> <li><a href="http://frickinsweet.com/ryanlanciaux.com/post/Very-Quick-and-Simple-Dependency-Injection-with-StructureMap.aspx"> Very Quick and Simple Dependency Injection with StructureMap</a> </li> - <li><a href="http://dimecasts.net/Casts/ByTag/StructureMap">StructureMap on + <li><a href="http://dimecasts.net/Casts/ByTag/StructureMap">StructureMap ScreenCasts on DimeCasts</a> </li> <li><a href="http://codebetter.com/blogs/jeremy.miller/archive/2008/10/25/initializing-and-configuring-a-structuremap-container.aspx"> Initializing and Configuring a StructureMap Container</a> </li> @@ -88,7 +93,7 @@ Integrating StructureMap with WCF</a> </li> </ul> - <p> </p> + <hr /> <p> </p> </body> Added: trunk/Source/HTML/DependencyInjection.htm =================================================================== --- trunk/Source/HTML/DependencyInjection.htm (rev 0) +++ trunk/Source/HTML/DependencyInjection.htm 2009-01-05 04:27:51 UTC (rev 216) @@ -0,0 +1,1076 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> + <head> + <title>Dependency Injection - What is it, and what is it good for?</title> + <link rel="stylesheet" type="text/css" href="style.css" /> + <script type="text/javascript" src="jquery-1.2.6.js"></script> + <script type="text/javascript" src="structuremap.js"></script> + <style type="text/css"> + .style1 + { + font-weight: normal; + } + </style> + </head> + <body> + + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + This was originally posted on + <a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/10/06/132825.aspx">Jeremy's blog</a> way back in 2005. A few things + have changed, specifically the possibility of using mocking tools that can mock + concrete classes and mock without using Dependency Injection (DI) -- but Jeremy + still thinks it's much cleaner to use DI ;-)</p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + </p> + <h2 style="margin: 0in 0in 0pt;"> + Dependency Injection</h2> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + </p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + Dependency Injection is a specific usage of the larger + <a href="InversionOfControl.htm">Inversion of Control</a> concept.<span style=""> </span>In a nutshell, dependency injection + just means that a given class or system is no longer responsible for + instantiating their own dependencies.<span style=""> </span>In this case + “Inversion of Control” refers to moving the responsibility for locating and + attaching dependency objects to another class or a DI tool.<span style=""> + </span>That might not sound that terribly profound, but it opens the door for a + lot of interesting scenarios.</p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <o:p> </o:p></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + While there’s a fair amount of unnecessary buzz and hype about the concept, I’ve + found Dependency Injection to be very advantageous for doing Test Driven + Development without pulling your hair out.<span style=""> </span>If you’ve + seen articles or blog posts about Dependency Injection but don’t quite + internalize the value of DI yet, here are the facts as I see them:</p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <o:p> </o:p></p> + <ol style="margin-top: 0in;" type="1"> + <li class="MsoNormal" style="margin: 0in 0in 0pt;">Dependency Injection is an + important pattern for creating classes that are easier to unit test in isolation</li> + <li class="MsoNormal" style="margin: 0in 0in 0pt;">Promotes loose coupling between + classes and subsystems </li> + <li class="MsoNormal" style="margin: 0in 0in 0pt;">Adds potential flexibility to a + codebase for future changes</li> + <li class="MsoNormal" style="margin: 0in 0in 0pt;">Can enable better code reuse</li> + <li class="MsoNormal" style="margin: 0in 0in 0pt;"><b style="">The implementation is + simple and does *not* require a fancy DI tool<o:p></o:p></b></li> + </ol> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <o:p> </o:p></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + The <a href="http://picocontainer.org/" mce_href="http://picocontainer.org/"> + PicoContainer</a> team even has silly tee shirts printed up that say “I expected + a paradigm shift, but all I got was a lousy constructor function.”<span + style=""> </span>DI is certainly a case where a minimum of effort + supplies quite a bit of benefit.<span style=""> </span>Don’t blow it off + just because it seems trivial.<span style=""> </span> + </p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <o:p> </o:p></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + There are tools out there that do Dependency Injection in .Net.<span style=""> + </span>I use my own tool called <a href="http://structuremap.sourceforge.net/" + mce_href="http://structuremap.sourceforge.net/">StructureMap</a> in my + development, but I’m going to focus on only the concept of DI in this post.</p> + <hr /> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <o:p> </o:p></p> + <h2 style="margin: 0in 0in 0pt;"> + <b style="">Example Problem<o:p></o:p></b></h2> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <b style=""><o:p> </o:p></b></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + My first experience with conscious usage of DI was a WinForms client + communicating with the backend via web services that was built with the + <a href="http://codebetter.com/blogs/jeremy.miller/articles/129546.aspx" + mce_href="http://codebetter.com/blogs/jeremy.miller/articles/129546.aspx"> + Model View Presenter</a> (“Humble Dialog Box”) architecture for easier unit + testing.<span style=""> </span>Most screens in the client end up with + something like this set of classes:</p> + <ul style="margin-top: 0in;" type="disc"> + <li class="MsoNormal" style="margin: 0in 0in 0pt;">Model – Whatever business + object/DataSet/chunk of data is being displayed or edited</li> + <li class="MsoNormal" style="margin: 0in 0in 0pt;">View – A WinForms UserControl + class.<span style=""> </span>Displays data to a user and captures user input + and screen events (duh).</li> + <li class="MsoNormal" style="margin: 0in 0in 0pt;">Service – A web service proxy + class to send requests to the backend</li> + <li class="MsoNormal" style="margin: 0in 0in 0pt;">Presenter – The controller class + that coordinates all of the above.</li> + </ul> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <o:p> </o:p></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + The presenter class without Dependency Injection might look like this.</p> + <div class="code-sample"> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <o:p> </o:p></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">public</span> <span style="color: blue;">class</span> + Presenter<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>{<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">private</span> View _view;<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">private</span> Model _model;<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><o:p> </o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">public</span> Presenter(){}<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><o:p> </o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">public</span> <span style="color: blue;"> + object</span> CreateView(Model model)<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>{<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>_model = model;<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>_view = <span style="color: blue;">new</span> View();<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>_view.DisplayModel(model);<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><o:p> </o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">return</span> _view;<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>}<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><o:p> </o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">public</span> <span style="color: blue;">void</span> + Close()<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>{<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">bool</span> canClose = + <span style="color: blue;">true</span>;<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><o:p></o:p></span> + </p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">if</span> (_view.IsDirty())<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>{<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>canClose = _view.CanCloseDirtyScreen();<span style=""> </span><o:p></o:p> + </span> + </p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>}<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><o:p> </o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">if</span> (canClose)<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>{<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>_view.Close();<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>}<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>}<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><o:p> </o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span><span style="color: blue;">public</span> <span style="color: blue;">void</span> + Save()<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>{<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>Service service = <span style="color: blue;">new</span> Service();<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>service.Persist(_model);<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>}<o:p></o:p></span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> + </span>}</span></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <o:p> </o:p></p> + +</div> + + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + </p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + This code cannot be unit tested in isolation because it has a tight coupling to + a concrete implementation of both the WinForms UserControl (View) and the proxy + class to a web service (Service).<span style=""> </span>This code as is + cannot function without both the User Interface and a web server running the + backend.<span style=""> </span>The point of using the MVP is to + isolate most of the user interface logic away from the WinForms and web service + mechanics to enable effective unit testing, so we’re missing something here.<span + style=""> </span>To unit test the presenter logic we’d like to replace + the user interface and web service dependencies with a + <a href="http://martinfowler.com/articles/mocksArentStubs.html" + mce_href="http://martinfowler.com/articles/mocksArentStubs.html">Mock</a> + object inside our test fixture classes.<span style=""> </span>In order to + mock the view and service, we first need to use the + <a href="http://codebetter.com/blogs/jeremy.miller/articles/129543.aspx" + mce_href="http://codebetter.com/blogs/jeremy.miller/articles/129543.aspx"> + Dependency Inversion Principle</a> to make the + <span style="font-family: 'Courier New';">Presenter</span> class depend on an + abstracted <span style="font-family: 'Courier New';">IView</span> and + <span style="font-family: 'Courier New';">IService</span> interface instead of + the concrete <span style="font-family: 'Courier New';">UserControl</span> and + <span style="font-family: 'Courier New';">WebProxy</span> classes.<span + style=""> </span>The next thing to do is to alter the + <span style="font-family: 'Courier New';">Presenter</span> class so that we can + substitute at run time the mock objects instead of the concrete classes within + the unit tests.<span style=""> </span>This is where Dependency Injection + comes into play.</p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + <o:p> </o:p></p> + <p class="MsoNormal" style="margin: 0in 0in 0pt;"> + There are a couple of different flavors of Dependency Injection (via + <a href="http://martinfowler.com/articles/injection.html" + mce_href="http://martinfowler.com/articles/injection.html">Martin Fowler</a> + + the Pico guys)</p> + <ol style="margin-top: 0in;" type="1"> + <li class="MsoNormal" style="margin: 0in 0in 0pt;">Constructor Injection – Attach + the dependencies through a constructor function at object creation</li> + <li class... [truncated message content] |