|
From: <jer...@us...> - 2008-10-18 20:49:28
|
Revision: 187
http://structuremap.svn.sourceforge.net/structuremap/?rev=187&view=rev
Author: jeremydmiller
Date: 2008-10-18 20:49:21 +0000 (Sat, 18 Oct 2008)
Log Message:
-----------
documentation
Modified Paths:
--------------
trunk/Source/CommonAssemblyInfo.cs
trunk/Source/HTML/Glossary.htm
trunk/Source/HTML/ScanningAssemblies.htm
trunk/Source/StructureMap/Graph/AssemblyScanner.cs
trunk/Source/StructureMap/Pipeline/Instance.cs
trunk/Source/StructureMap.Testing/Examples.cs
Modified: trunk/Source/CommonAssemblyInfo.cs
===================================================================
--- trunk/Source/CommonAssemblyInfo.cs 2008-10-18 13:26:11 UTC (rev 186)
+++ trunk/Source/CommonAssemblyInfo.cs 2008-10-18 20:49:21 UTC (rev 187)
@@ -5,7 +5,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:2.0.50727.1433
+// Runtime Version:2.0.50727.1434
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
Modified: trunk/Source/HTML/Glossary.htm
===================================================================
--- trunk/Source/HTML/Glossary.htm 2008-10-18 13:26:11 UTC (rev 186)
+++ trunk/Source/HTML/Glossary.htm 2008-10-18 20:49:21 UTC (rev 187)
@@ -184,8 +184,122 @@
<!--EndFragment-->
<p> </p>
<h4>Instance</h4>
- <p>In StructureMap terms, an "Instance" is a named way to build or locate an object
- instance for a requested PluginType. There is an actual class in
+ <p>In StructureMap terms, an "Instance" is a named way to build or locate a
+ named object
+ instance for a requested PluginType. An "Instance" does not automatically
+ equate to a concrete type. For example, let's say that we're building a
+ system to automate a warehouse. Our system might consume an interface
+ called IShippingService that acts as a Gateway[LINK] to various ways of shipping
+ boxes out of our warehouse.</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20 \cf3 public\cf0 \cf3 interface\cf0 \cf4 IShippingService\par ??\cf0 \{\par ?? \cf3 void\cf0 ShipIt();\par ?? \}}
+-->
+ <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ <span style="color: blue;">public</span> <span style="color: blue;">
+ interface</span> <span style="color: #2b91af;">IShippingService</span></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">void</span> ShipIt();</p>
+ <p style="margin: 0px;">
+ }</p>
+ </div>
+<!--EndFragment-->
+<p>Our warehouse system might have to interact with three types of shipping:
+ domestic, international, and intra-company or internal shipments. The
+ internal shipping service runs in process with the warehouse application, but
+ domestic and international shipping is done by invoking external web services.
+ The registration of the IShippingService Instances might look like this:</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20 \cf3 public\cf0 \cf3 class\cf0 \cf4 ShippingRegistry\cf0 : \cf4 Registry\par ??\cf0 \{\par ?? \cf3 public\cf0 ShippingRegistry()\par ?? \{\par ?? ForRequestedType<\cf4 IShippingService\cf0 >().AddInstances(x =>\par ?? \{\par ?? x.OfConcreteType<\cf4 ShippingWebService\cf0 >()\par ?? .WithCtorArg(\cf5 "url"\cf0 ).EqualTo(\cf5 "a url"\cf0 )\par ?? .WithName(\cf5 "Domestic"\cf0 );\par ??\par ?? x.OfConcreteType<\cf4 ShippingWebService\cf0 >()\par ?? .WithCtorArg(\cf5 "url"\cf0 ).EqualTo(\cf5 "a different url"\cf0 )\par ?? .WithName(\cf5 "International"\cf0 );\par ??\par ?? x.OfConcreteType<\cf4 InternalShippingService\cf0 >().WithName(\cf5 "Internal"\cf0 );\par ?? \});\par ?? \}\par ?? \}}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ <span style="color: blue;">public</span> <span style="color: blue;">
+ class</span> <span style="color: #2b91af;">ShippingRegistry</span> :
+ <span style="color: #2b91af;">Registry</span></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">public</span>
+ ShippingRegistry()</p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+ ForRequestedType<<span
+ style="color: #2b91af;">IShippingService</span>>().AddInstances(x =></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+
+ x.OfConcreteType<<span style="color: #2b91af;">ShippingWebService</span>>()</p>
+ <p style="margin: 0px;">
+
+ .WithCtorArg(<span style="color: #a31515;">"url"</span>).EqualTo(<span
+ style="color: #a31515;">"a url"</span>)</p>
+ <p style="margin: 0px;">
+
+ .WithName(<span style="color: #a31515;">"Domestic"</span>);</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ x.OfConcreteType<<span style="color: #2b91af;">ShippingWebService</span>>()</p>
+ <p style="margin: 0px;">
+
+ .WithCtorArg(<span style="color: #a31515;">"url"</span>).EqualTo(<span
+ style="color: #a31515;">"a different url"</span>)</p>
+ <p style="margin: 0px;">
+
+ .WithName(<span style="color: #a31515;">"International"</span>);</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ x.OfConcreteType<<span style="color: #2b91af;">InternalShippingService</span>>().WithName(<span
+ style="color: #a31515;">"Internal"</span>);</p>
+ <p style="margin: 0px;">
+ });</p>
+ <p style="margin: 0px;">
+ }</p>
+ <p style="margin: 0px;">
+ }</p>
+</div>
+<!--EndFragment-->
+<p>In the registration code above, there are three "Instance's." You can
+ access the various IShippingService Instance's by name:</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green128\blue0;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20 \cf3 // Accessing the IShippingService Instance's by name\par ??\cf0 \cf4 var\cf0 internationalService = \cf5 ObjectFactory\cf0 .GetNamedInstance<\cf5 IShippingService\cf0 >(\cf6 "International"\cf0 );\par ?? \cf4 var\cf0 domesticService = \cf5 ObjectFactory\cf0 .GetNamedInstance<\cf5 IShippingService\cf0 >(\cf6 "Domestic"\cf0 );\par ?? \cf4 var\cf0 internalService = \cf5 ObjectFactory\cf0 .GetNamedInstance<\cf5 IShippingService\cf0 >(\cf6 "Internal"\cf0 );\par ??}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// Accessing the IShippingService Instance's by name</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: blue;">var</span> internationalService =
+ <span style="color: #2b91af;">ObjectFactory</span>.GetNamedInstance<<span
+ style="color: #2b91af;">IShippingService</span>>(<span
+ style="color: #a31515;">"International"</span>);</p>
+ <p style="margin: 0px;">
+
+ <span style="color: blue;">var</span> domesticService =
+ <span style="color: #2b91af;">ObjectFactory</span>.GetNamedInstance<<span
+ style="color: #2b91af;">IShippingService</span>>(<span
+ style="color: #a31515;">"Domestic"</span>);</p>
+ <p style="margin: 0px;">
+
+ <span style="color: blue;">var</span> internalService =
+ <span style="color: #2b91af;">ObjectFactory</span>.GetNamedInstance<<span
+ style="color: #2b91af;">IShippingService</span>>(<span
+ style="color: #a31515;">"Internal"</span>);</p>
+</div>
+<!--EndFragment-->
+<p>Asking for the "International" or the "Domestic" instance of IShippingService
+ will both return an object of type ShippingWebService, but the two objects will
+ be differently configured with unique Url's.</p>
+<p>There is an actual class in
StructureMap 2.5 that represents an "Instance." An abreviated version of
the abstract Instance class is shown below:</p>
<!--
@@ -296,16 +410,212 @@
method to create a new object or get an existing object. Note the abstract
build(Type, IBuildSession) method. This is a Template Method that can be
overriden to write your own customized Instance type.</p>
-<p>When you call ObjectFactory.Get</p>
- <h4>Scoping</h4>
- <p>a;lskdfje</p>
- <h4>PluginFamily</h4>
- <p>a;lskdfj</p>
- <h4>Profile</h4>
- <p>a;lskdfj</p>
+<p>When you call ObjectFactory.GetNamedInstance<T>("the instance that I want") or
+ ObjectFactory.GetInstance<T>(), the internal Container object is locating the
+ correct Instance object and calling its Build() method.</p>
+ <h4>Scoping (or Lifecycle)</h4>
+ <p>When you register a PluginType in the system you can "scope" the Instance's of
+ that PluginType like this:</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green128\blue0;\red43\green145\blue175;}??\fs20 \cf3 // This is used as a sort of lightweight ScriptManager in\par ??\cf0 \cf3 // our website application\par ??\cf0 ForRequestedType<\cf4 ICachedSet\cf0 >().TheDefaultIsConcreteType<\cf4 CachedSet\cf0 >()\par ?? .CacheBy(\cf4 InstanceScope\cf0 .Hybrid);\par ??}
+-->
+ <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// This is used as a sort of lightweight
+ ScriptManager in</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// our website application</span></p>
+ <p style="margin: 0px;">
+ ForRequestedType<<span
+ style="color: #2b91af;">ICachedSet</span>>().TheDefaultIsConcreteType<<span
+ style="color: #2b91af;">CachedSet</span>>()</p>
+ <p style="margin: 0px;">
+
+ .CacheBy(<span style="color: #2b91af;">InstanceScope</span>.HttpContext);</p>
+ </div>
+<!--EndFragment-->
+<p>Note the CacheBy() method hanging off the end of the expression. This is
+ directing the StructureMap container to use the same object instance for
+ ICachedSet for all requests in the same HttpContext. In this case, if a
+ request is made for any Instance of ICachedSet, StructureMap will first check
+ the HttpContext.Items collection to see if that exact Instance has already been
+ created within the same HttpContext. </p>
+ <ol>
+ <li>PerRequest - The default option unless otherwise overridden. A new object
+ will be created for each time you request an Instance from the container.
+ Some other IoC containers call this "Transient." Please note that this is
+ the default behavior in StructureMap. Many other IoC container tools will
+ use "Singleton" instead. </li>
+ <li>Singleton - A single object will be shared across
+ all requests for a specific Instance. StructureMap will only create the
+ singleton object upon demand</li>
+ <li>ThreadLocal - A single object will be created for
+ each requesting thread. Caches the instances with
+ ThreadLocalStorage.</li>
+ <li>HttpContext - A single object will be created for
+ each HttpContext. Caches the instances in the
+ HttpContext.Items collection.</li>
+ <li>Hybrid - Uses HttpContext storage if it exists,
+ otherwise uses ThreadLocal storage.</li>
+ </ol>
+ <p>
+ It is possible to create your own type of scoping. See "Extending
+ StructureMap" [LINK -- doesn't exist yet] for more information. Also note
+ that StructureMap provides no functionality for cleaning up resources of the
+ objects held by the container. To date, I have not found a need for this
+ behavior or functionality. I generally assume that a combination of basic
+ garbage collection and proper class design is sufficient.</p>
+ <h4> </h4>
+ <h4>Profile</h4>
+ <p>From the very beginning, StructureMap has supported the ability to define a named
+ set of default instances called a "Profile." The Profile feature was
+ originally meant to be a quick way of switching the connection mode of a smart
+ client application from connected to disconnected modes. In practice, it's
+ more commonly used as a way to migrate configuration between environments or for
+ creating alternative deployment configurations. My team uses the Profile
+ feature in our system as a quick way to collapse our entire distributed
+ application into a single AppDomain for easier testing and debugging. Our
+ "InMemory" profile is defined like this:</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green128\blue0;\red0\green0\blue255;\red43\green145\blue175;}??\fs20 \cf3 // Using this Profile configures our application to \par ??\cf0 \cf3 // run completely inside a single AppDomain\par ??\cf0 \cf3 // In production the application will consist\par ??\cf0 \cf3 // of the website and 2-3 external windows\par ??\cf0 \cf3 // services\par ??\cf0 \cf4 var\cf0 repository = \cf4 new\cf0 \cf5 InMemoryRepository\cf0 ();\par ?? CreateProfile(IN_MEMORY_PROFILE, x =>\par ?? \{\par ?? x.For<\cf5 IRepository\cf0 >().Use(repository);\par ?? x.For<\cf5 IEventPublishingService\cf0 >().Use(\cf4 new\cf0 \cf5 InMemoryEventPublishingService\cf0 (repository));\par ?? x.For<\cf5 IUserMessagePublisher\cf0 >().UseConcreteType<\cf5 InMemoryUserMessageQueue\cf0 >();\par ?? x.For<\cf5 IUnitOfWork\cf0 >().UseConcreteType<\cf5 InMemoryUnitOfWork\cf0 >();\par ?? \});}
+-->
+ <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// Using this Profile configures our application to
+ </span>
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// run completely inside a single AppDomain</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// In production the application will consist</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// of the website and 2-3 external windows</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// services</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: blue;">var</span> repository = <span style="color: blue;">
+ new</span> <span style="color: #2b91af;">InMemoryRepository</span>();</p>
+ <p style="margin: 0px;">
+
+ CreateProfile(IN_MEMORY_PROFILE, x =></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+
+ x.For<<span style="color: #2b91af;">IRepository</span>>().Use(repository);</p>
+ <p style="margin: 0px;">
+
+ x.For<<span style="color: #2b91af;">IEventPublishingService</span>>().Use(<span
+ style="color: blue;">new</span> <span style="color: #2b91af;">
+ InMemoryEventPublishingService</span>(repository));</p>
+ <p style="margin: 0px;">
+
+ x.For<<span style="color: #2b91af;">IUserMessagePublisher</span>>().UseConcreteType<<span
+ style="color: #2b91af;">InMemoryUserMessageQueue</span>>();</p>
+ <p style="margin: 0px;">
+
+ x.For<<span style="color: #2b91af;">IUnitOfWork</span>>().UseConcreteType<<span
+ style="color: #2b91af;">InMemoryUnitOfWork</span>>();</p>
+ <p style="margin: 0px;">
+ });</p>
+ </div>
+<!--EndFragment-->
+<p>In the code, we can switch the application to the in memory mode by calling the
+ SetDefaultsToProfile() method on the Container (or ObjectFactory.Profile =
+ CoreRegistry.IN_MEMORY_PROFILE):</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green128\blue0;\red43\green145\blue175;\red0\green0\blue255;}??\fs20 \cf3 // This is actual code from a test harness class we use\par ??\cf0 \cf3 // for integration testing\par ??\cf0 \cf4 IContainer\cf0 container = createContainer(\cf5 new\cf0 \cf4 RuleSet\cf0 []\{ruleSet\});\par ?? container.SetDefaultsToProfile(\cf4 CoreRegistry\cf0 .IN_MEMORY_PROFILE);\par ??}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// This is actual code from a test harness class we
+ use</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// for integration testing</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: #2b91af;">IContainer</span> container = createContainer(<span
+ style="color: blue;">new</span> <span style="color: #2b91af;">RuleSet</span>[]{ruleSet});</p>
+ <p style="margin: 0px;">
+
+ container.SetDefaultsToProfile(<span style="color: #2b91af;">CoreRegistry</span>.IN_MEMORY_PROFILE);</p>
+</div>
+<!--EndFragment-->
+<p> </p>
<h4>Interceptor</h4>
- <p>a;lskdfj</p>
- <h4>PostProcessor</h4>
- <p>a;lskdfj</p>
+ <p>A new feature for StructureMap 2.5 is the ability to "intercept" an object
+ getting created in StructureMap before the new object is handed back to the
+ requesting code. The intention behind this feature is to support runtime
+ Aspect Oriented Programming techniques or any type of object initialization
+ beyond the constructor function. </p>
+ <p>
+ To explain the sequence of events, here's an ellided version of the Build()
+ method of the Instance abstract class:</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;}??\fs20 \cf3 public\cf0 \cf3 virtual\cf0 \cf3 object\cf0 Build(\cf4 Type\cf0 pluginType, \cf4 BuildSession\cf0 session)\par ?? \{\par ?? markBuildStackStart(session, pluginType);\par ??\par ?? \cf5 // "Build" the desired object\par ??\cf0 \cf3 object\cf0 rawValue = createRawObject(pluginType, session);\par ?? \par ?? \cf5 // Allow the Interceptor a chance to enhance, configure, \par ??\cf0 \cf5 // wrap with a decorator, or even replace the rawValue\par ??\cf0 \cf3 object\cf0 finalValue = applyInterception(rawValue, pluginType);\par ??\par ?? markBuildStackFinish(session);\par ??\par ?? \cf3 return\cf0 finalValue;\par ?? \}}
+-->
+ <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ <span style="color: blue;">public</span>
+ <span style="color: blue;">virtual</span> <span style="color: blue;">object</span>
+ Build(<span style="color: #2b91af;">Type</span> pluginType,
+ <span style="color: #2b91af;">BuildSession</span> session)</p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+
+ markBuildStackStart(session, pluginType);</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// "Build" the desired object</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: blue;">object</span> rawValue = createRawObject(pluginType,
+ session);</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// Allow the Interceptor a chance to enhance,
+ configure, </span>
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// wrap with a decorator, or even replace the
+ rawValue</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: blue;">object</span> finalValue =
+ applyInterception(rawValue, pluginType);</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ markBuildStackFinish(session);</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: blue;">return</span> finalValue;</p>
+ <p style="margin: 0px;">
+ }</p>
+ </div>
+<!--EndFragment-->
+<p>
+ The Instance class first builds the raw object, then applies any registered
+ interception on the raw object to get the final value.
+</p>
</body>
</html>
\ No newline at end of file
Modified: trunk/Source/HTML/ScanningAssemblies.htm
===================================================================
--- trunk/Source/HTML/ScanningAssemblies.htm 2008-10-18 13:26:11 UTC (rev 186)
+++ trunk/Source/HTML/ScanningAssemblies.htm 2008-10-18 20:49:21 UTC (rev 187)
@@ -92,8 +92,16 @@
<p>
The actual work is performed by an IAssemblyScanner object. The Scan()
method uses the <a href="http://martinfowler.com/dslwip/NestedClosure.html">
- Nested Closure</a> pattern as a way of configuring the IAssemblyScanner and then
- executing the scanner at the correct time in the configuration process.
+ Nested Closure</a> pattern as a way of configuring and registering the IAssemblyScanner
+ in a single atomic action. Each Scan() expression is a completely
+ self-contained, atomic action. This is a significant change from the
+ earlier functionality in versions 2.0 and 2.4.9. This breaking change was
+ made to reduce confusion by making the actual functionality more closely match
+ the DSL expression. </p>
+<p>
+ The scanner itself will not be executed until near the end of the configuration process.
+ Be aware of this issue if you are trying to debug custom ITypeScanner classes.</p>
+<p>
The IAssemblyScanner interface exposes these directives to control the assembly
scanning:</p>
<!--
@@ -188,55 +196,624 @@
</div>
<!--EndFragment-->
<p>
- </p>
+ Roughly put, these are the features and options of each individual Scan()
+ expression:</p>
+<ol>
+ <li>Analyzing all the exported types in the specified Assembly's</li>
+ <li>By default, looking for all types decorated with either the [PluginFamily] or
+ [Pluggable] attributes. This feature can be disabled by calling the
+ IAssemblyScanner.IgnoreStructureMapAttributes() method. See NEED A LINK
+ HERE for more information</li>
+ <li><b>If explicitly specified</b> with the use of the LookForRegistries() method,
+ the scanning will apply the configuration contained within any concrete Registry
+ class found in the assemblies being scanned.</li>
+ <li>Optionally, the scanning can automatically add any concrete types found that can
+ be "plugged" into a given PluginType</li>
+ <li>The scanning of types within an Assembly can be further filtered by specifying
+ rules to either include or exclude types based on Predicate<Type> rules[LINK].</li>
+ <li>Lastly, custom scanning conventions and policies can be added and used from the
+ Scan() expression. </li>
+</ol>
<h4>
Rules for Auto Registering a Type</h4>
+<p>
+ If you are interested in using the Scan() expression for auto registration, the
+ first thing to know is how StructureMap determines whether or not a given
+ concrete type should be registered. </p>
+<p>
+ </p>
+<ul>
+ <li>The PluginType is assignable from the concrete type</li>
+ <li>The concrete type has a public constructor</li>
+ <li>Cannot have a primitive constructor argument</li>
+ <li>Auto scanning only works if there is only one concrete type registered for a
+ PluginType</li>
+ <li>The scanning can be overridden explicitly</li>
+</ul>
<h4>
- Designating Assemblies <h4>
+ Designating Assemblies
+<p>
+ The first thing you need to do to utilize the type scanning is to designate
+ which assemblies to scan. The type scanning will throw an exception if you
+ attempt to call the Scan() expression without designating at least one assembly.
+ Use one of the following methods on IAssemblyScanner to designate assemblies:\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;}??\fs20 \cf3 public\cf0 \cf3 interface\cf0 \cf4 IAssemblyScanner\par ??\cf0 \{\par ?? \cf5 // Determining which assemblies to scan\par ??\cf0 \cf3 void\cf0 Assembly(\cf4 Assembly\cf0 assembly);\par ?? \cf3 void\cf0 Assembly(\cf3 string\cf0 assemblyName);\par ?? \cf3 void\cf0 TheCallingAssembly();\par ?? \cf3 void\cf0 AssemblyContainingType<T>();\par ?? \cf3 void\cf0 AssemblyContainingType(\cf4 Type\cf0 type);\par ?? \cf3 void\cf0 AssembliesFromPath(\cf3 string\cf0 path);\par ?? \cf3 void\cf0 AssembliesFromPath(\cf3 string\cf0 path, \cf4 Predicate\cf0 <\cf4 Assembly\cf0 > assemblyFilter);\par ?? \par ?? \cf5 // Adding conventions\par ??\cf0 \cf3 void\cf0 With(\cf4 ITypeScanner\cf0 scanner);\par ?? \cf3 void\cf0 WithDefaultConventions();\par ?? \cf3 void\cf0 With<T>() \cf3 where\cf0 T : \cf4 ITypeScanner\cf0 , \cf3 new\cf0 ();\par ?? \par ?? \cf5 // Other options\par ??\cf0 \cf3 void\cf0 LookForRegistries();\par ?? \cf3 void\cf0 AddAllTypesOf<PLUGINTYPE>();\par ?? \cf3 void\cf0 AddAllTypesOf(\cf4 Type\cf0 pluginType);\par ?? \cf3 void\cf0 IgnoreStructureMapAttributes();\par ?? \par ?? \cf5 // Filtering the types that will be scanned\par ??\cf0 \cf3 void\cf0 Exclude(\cf4 Predicate\cf0 <\cf4 Type\cf0 > exclude);\par ?? \cf3 void\cf0 ExcludeNamespace(\cf3 string\cf0 nameSpace);\par ?? \cf3 void\cf0 ExcludeNamespaceContainingType<T>();\par ?? \cf3 void\cf0 Include(\cf4 Predicate\cf0 <\cf4 Type\cf0 > predicate);\par ?? \cf3 void\cf0 IncludeNamespace(\cf3 string\cf0 nameSpace);\par ?? \cf3 void\cf0 IncludeNamespaceContainingType<T>();\par ?? \cf3 void\cf0 ExcludeType<T>();\par ?? \}}
+-->
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;}??\fs20 \cf3 public\cf0 \cf3 interface\cf0 \cf4 IAssemblyScanner\par ??\cf0 \{\par ??\cf3 #region\cf0 Designating Assemblies\par ??\par ?? \cf3 void\cf0 Assembly(\cf4 Assembly\cf0 assembly);\par ?? \cf3 void\cf0 Assembly(\cf3 string\cf0 assemblyName);\par ?? \cf3 void\cf0 TheCallingAssembly();\par ?? \cf3 void\cf0 AssemblyContainingType<T>();\par ?? \cf3 void\cf0 AssemblyContainingType(\cf4 Type\cf0 type);\par ?? \cf3 void\cf0 AssembliesFromPath(\cf3 string\cf0 path);\par ?? \cf3 void\cf0 AssembliesFromPath(\cf3 string\cf0 path, \cf4 Predicate\cf0 <\cf4 Assembly\cf0 > assemblyFilter);\par ??\par ??\cf3 #endregion\par ??\par ??\cf0 \cf5 // ... Other methods\par ??\par ??\cf3 #region\cf0 Adding TypeScanners\par ??\par ?? \cf3 void\cf0 With(\cf4 ITypeScanner\cf0 scanner);\par ?? \cf3 void\cf0 WithDefaultConventions();\par ?? \cf3 void\cf0 With<T>() \cf3 where\cf0 T : \cf4 ITypeScanner\cf0 , \cf3 new\cf0 ();\par ??\par ??\cf3 #endregion\par ??\par ?? #region\cf0 Other options\par ??\par ?? \cf3 void\cf0 LookForRegistries();\par ?? \cf3 void\cf0 AddAllTypesOf<PLUGINTYPE>();\par ?? \cf3 void\cf0 AddAllTypesOf(\cf4 Type\cf0 pluginType);\par ?? \cf3 void\cf0 IgnoreStructureMapAttributes();\par ??\par ??\cf3 #endregion\par ??\par ?? #region\cf0 Filtering types\par ??\par ?? \cf3 void\cf0 Exclude(\cf4 Predicate\cf0 <\cf4 Type\cf0 > exclude);\par ?? \cf3 void\cf0 ExcludeNamespace(\cf3 string\cf0 nameSpace);\par ?? \cf3 void\cf0 ExcludeNamespaceContainingType<T>();\par ?? \cf3 void\cf0 Include(\cf4 Predicate\cf0 <\cf4 Type\cf0 > predicate);\par ?? \cf3 void\cf0 IncludeNamespace(\cf3 string\cf0 nameSpace);\par ?? \cf3 void\cf0 IncludeNamespaceContainingType<T>();\par ?? \cf3 void\cf0 ExcludeType<T>();\par ??\par ??\cf3 #endregion\par ??\par ??\cf0 \}}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ <span style="color: blue;">public</span> <span style="color: blue;">
+ interface</span> <span style="color: #2b91af;">IAssemblyScanner</span></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">void</span>
+ Assembly(<span style="color: #2b91af;">Assembly</span> assembly);</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">void</span>
+ Assembly(<span style="color: blue;">string</span> assemblyName);</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">void</span>
+ TheCallingAssembly();</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">void</span>
+ AssemblyContainingType<T>();</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">void</span>
+ AssemblyContainingType(<span style="color: #2b91af;">Type</span> type);</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">void</span>
+ AssembliesFromPath(<span style="color: blue;">string</span> path);</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">void</span>
+ AssembliesFromPath(<span style="color: blue;">string</span> path,
+ <span style="color: #2b91af;">Predicate</span><<span style="color: #2b91af;">Assembly</span>>
+ assemblyFilter);</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+ <span style="color: green;">// ... Other methods</span></p>
+ <p style="margin: 0px;">
+ }</p>
+ </div>
+<!--EndFragment-->
+<p>
+ Adding an assembly directly:</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;\red163\green21\blue21;}??\fs20 \cf3 public\cf0 \cf3 class\cf0 \cf4 ScanningRegistry\cf0 : \cf4 Registry\par ??\cf0 \{\par ?? \cf3 public\cf0 ScanningRegistry()\par ?? \{\par ?? Scan(x =>\par ?? \{\par ?? \cf5 // Add assembly by name.\par ??\cf0 x.Assembly(\cf6 "StructureMap.Testing.Widget"\cf0 );\par ??\par ?? \cf5 // Add an assembly directly\par ??\cf0 x.Assembly(\cf4 Assembly\cf0 .GetExecutingAssembly());\par ??\par ?? \cf5 // Add the assembly that contains a certain type\par ??\cf0 x.AssemblyContainingType<\cf4 IService\cf0 >();\par ?? \cf5 // or\par ??\cf0 x.AssemblyContainingType(\cf3 typeof\cf0 (\cf4 IService\cf0 ));\par ?? \});\par ?? \}\par ?? \}}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ <span style="color: blue;">public</span> <span style="color: blue;">
+ class</span> <span style="color: #2b91af;">ScanningRegistry</span> :
+ <span style="color: #2b91af;">Registry</span></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">public</span>
+ ScanningRegistry()</p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+ Scan(x =></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// Add assembly by name.</span></p>
+ <p style="margin: 0px;">
+
+ x.Assembly(<span style="color: #a31515;">"StructureMap.Testing.Widget"</span>);</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// Add an assembly directly</span></p>
+ <p style="margin: 0px;">
+
+ x.Assembly(<span style="color: #2b91af;">Assembly</span>.GetExecutingAssembly());</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// Add the assembly that contains a certain type</span></p>
+ <p style="margin: 0px;">
+
+ x.AssemblyContainingType<<span style="color: #2b91af;">IService</span>>();</p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// or</span></p>
+ <p style="margin: 0px;">
+
+ x.AssemblyContainingType(<span style="color: blue;">typeof</span>(<span
+ style="color: #2b91af;">IService</span>));</p>
+ <p style="margin: 0px;">
+ });</p>
+ <p style="margin: 0px;">
+ }</p>
+ <p style="margin: 0px;">
+ }</p>
+</div>
+<!--EndFragment-->
+<p>
+ The most common usage is probably just specifying "this" assembly with
+ IAssemblyScanner.TheCallingAssembly():</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;}??\fs20 \cf3 public\cf0 \cf3 class\cf0 \cf4 WebCoreRegistry\cf0 : \cf4 Registry\par ??\cf0 \{\par ?? \cf3 protected\cf0 \cf3 override\cf0 \cf3 void\cf0 configure()\par ?? \{\par ?? ForRequestedType<\cf4 ICachedSet\cf0 >().TheDefaultIsConcreteType<\cf4 CachedSet\cf0 >().CacheBy(\cf4 InstanceScope\cf0 .Hybrid);\par ?? ForRequestedType<\cf4 IControlBuilder\cf0 >().TheDefault.Is.OfConcreteType<\cf4 AspNetControlBuilder\cf0 >();\par ?? ForRequestedType<\cf4 IPartialRenderer\cf0 >().TheDefault.Is.OfConcreteType<\cf4 PartialRenderer\cf0 >();\par ??\par ?? Scan(x =>\par ?? \{\par ?? \cf5 // Scan "this" assembly. In other words, the assembly that \par ??\cf0 \cf5 // contains the WebCoreRegistry class\par ??\cf0 x.TheCallingAssembly();\par ??\par ?? x.IncludeNamespaceContainingType<\cf4 AuthenticationContext\cf0 >();\par ?? x.IncludeNamespaceContainingType<\cf4 ISecurityDataService\cf0 >();\par ??\par ?? x.WithDefaultConventions();\par ?? \});\par ?? \}\par ?? \}}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ <span style="color: blue;">public</span> <span style="color: blue;">
+ class</span> <span style="color: #2b91af;">WebCoreRegistry</span> :
+ <span style="color: #2b91af;">Registry</span></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">protected</span>
+ <span style="color: blue;">override</span> <span style="color: blue;">void</span>
+ configure()</p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+ ForRequestedType<<span
+ style="color: #2b91af;">ICachedSet</span>>().TheDefaultIsConcreteType<<span
+ style="color: #2b91af;">CachedSet</span>>().CacheBy(<span
+ style="color: #2b91af;">InstanceScope</span>.Hybrid);</p>
+ <p style="margin: 0px;">
+ ForRequestedType<<span
+ style="color: #2b91af;">IControlBuilder</span>>().TheDefault.Is.OfConcreteType<<span
+ style="color: #2b91af;">AspNetControlBuilder</span>>();</p>
+ <p style="margin: 0px;">
+ ForRequestedType<<span
+ style="color: #2b91af;">IPartialRenderer</span>>().TheDefault.Is.OfConcreteType<<span
+ style="color: #2b91af;">PartialRenderer</span>>();</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+ Scan(x =></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// Scan "this" assembly. In other words, the
+ assembly that </span>
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// contains the WebCoreRegistry class</span></p>
+ <p style="margin: 0px;">
+
+ x.TheCallingAssembly();</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ x.IncludeNamespaceContainingType<<span style="color: #2b91af;">AuthenticationContext</span>>();</p>
+ <p style="margin: 0px;">
+
+ x.IncludeNamespaceContainingType<<span style="color: #2b91af;">ISecurityDataService</span>>();</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ x.WithDefaultConventions();</p>
+ <p style="margin: 0px;">
+ });</p>
+ <p style="margin: 0px;">
+ }</p>
+ <p style="margin: 0px;">
+ }</p>
+</div>
+<p>
+ StructureMap 2.5 has a brand new capability to auto register types in all
+ assemblies in a given folder path. My current project is using this
+ feature for our extensibility mechanism. For customer-specific
+ deployments, we need to add business rules and even all new screens and features
+ to our application that can be discovered at runtime -- without changing our
+ core code. Our design calls for all extensions to be created in separate
+ assemblies. On application startup, our system will look for all
+ assemblies in a well known folder and use StructureMap to scan these assemblies
+ for the extensions that will be specified in Registry classes. Our
+ bootstrapping looks like:</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green128\blue0;\red163\green21\blue21;}??\fs20 Scan(x =>\par ?? \{\par ?? \cf3 // I'm telling StructureMap to sweep a folder called "Extensions" directly\par ??\cf0 \cf3 // underneath the application root folder for any assemblies\par ??\cf0 x.AssembliesFromPath(\cf4 "Extensions"\cf0 );\par ??\par ?? \cf3 // I also direct StructureMap to add any Registries that it finds in these\par ??\cf0 \cf3 // assemblies. I'm assuming that all the StructureMap directives are\par ??\cf0 \cf3 // contained in Registry classes -- and this is the recommended approach\par ??\cf0 x.LookForRegistries();\par ?? \});}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ Scan(x =></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// I'm telling StructureMap to sweep a folder called
+ "Extensions" directly</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// underneath the application root folder for any
+ assemblies found in that folder</span></p>
+ <p style="margin: 0px;">
+
+ x.AssembliesFromPath(<span style="color: #a31515;">"Extensions"</span>);</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// I also direct StructureMap to add any Registries
+ that it finds in these</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// assemblies. I'm assuming that all the
+ StructureMap directives are</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// contained in Registry classes -- and this is the
+ recommended approach</span></p>
+ <p style="margin: 0px;">
+
+ x.LookForRegistries();</p>
+ <p style="margin: 0px;">
+ });</p>
+</div>
+<!--EndFragment-->
+<p>
+ Note in the code above that I made an explicit call to "LookForRegistries."
+ Scanning for Registry's is no longer active by default. This is a breaking
+ change from the 2.4.9 preview release.
+</p>
+<p>
+ You can also filter the assemblies based on a Predicate like this:</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green128\blue0;\red163\green21\blue21;}??\fs20 Scan(x =>\par ?? \{\par ?? \cf3 // This time I'm going to specify a filter on the assembly such that \par ??\cf0 \cf3 // only assemblies that have "Extension" in their name will be scanned\par ??\cf0 x.AssembliesFromPath(\cf4 "Extensions"\cf0 , assembly => assembly.GetName().Name.Contains(\cf4 "Extension"\cf0 ));\par ??\par ?? x.LookForRegistries();\par ?? \});}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ Scan(x =></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// This time I'm going to specify a filter on the
+ assembly such that </span>
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// only assemblies that have "Extension" in their
+ name will be scanned</span></p>
+ <p style="margin: 0px;">
+
+ x.AssembliesFromPath(<span style="color: #a31515;">"Extensions"</span>, assembly
+ => assembly.GetName().Name.Contains(<span style="color: #a31515;">"Extension"</span>));</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ x.LookForRegistries();</p>
+ <p style="margin: 0px;">
+ });</p>
+</div>
+<!--EndFragment-->
+<p>
+ </p>
+<p>
+ </p>
+<h4>
Add All Concrete Types for a PluginType</h4>
+<p>
+ Sometimes you may simply want to automatically add all the concrete classes that
+ implement or inherit from a given PluginType. In my current project we are
+ using StructureMap to bootstrap and configure NHibernate. We're also using
+ Fluent NHibernate for our mapping configuration. The mapping configuration
+ is specified in classes that implement an interface named IDomainMap. To
+ configure NHibernate, we need to sweep our core assembly to find all concrete
+ implementations of IDomainMap and execute the mappings on each type. We
+ have a Registry called "CoreRegistry" that configures NHibernate (among other
+ things). We specify the auto registration of all the IDomainMap types like
+ this:</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green128\blue0;\red43\green145\blue175;}??\fs20 Scan(x =>\par ?? \{\par ?? \cf3 // Scan the types in the assembly that contains this Registry class\par ??\cf0 x.TheCallingAssembly();\par ??\par ?? x.ExcludeNamespaceContainingType<\cf4 IEvent\cf0 >();\par ?? x.ExcludeNamespaceContainingType<\cf4 SearchModel\cf0 >();\par ?? x.ExcludeNamespaceContainingType<\cf4 AuthenticationService\cf0 >();\par ?? x.ExcludeNamespaceContainingType<\cf4 DovetailController\cf0 >();\par ??\par ?? \cf3 // Finds and adds all concrete implementations of the IDomainMap\par ??\cf0 \cf3 // interface in the targetted assemblies\par ??\cf0 x.AddAllTypesOf<\cf4 IDomainMap\cf0 >();\par ?? x.WithDefaultConventions();\par ?? x.With<\cf4 DomainEntityAliaser\cf0 >();\par ?? \});}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ Scan(x =></p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// Scan the types in the assembly that contains this
+ Registry class</span></p>
+ <p style="margin: 0px;">
+
+ x.TheCallingAssembly();</p>
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// Finds and adds all concrete implementations of
+ the IDomainMap</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// interface in the targetted assemblies</span></p>
+ <p style="margin: 0px;">
+
+ x.AddAllTypesOf<<span style="color: #2b91af;">IDomainMap</span>>();</p>
+ <p style="margin: 0px;">
+ });</p>
+</div>
+<!--EndFragment-->
+<p>
+ After running the Scan() statement above, we can retrieve an instance of all the
+ IDomainMap types by calling:</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green128\blue0;\red43\green145\blue175;}??\fs20 \par ?? \cf3 // Retrieve all registered IDomainMap objects\par ??\cf0 \cf4 IList\cf0 <\cf4 IDomainMap\cf0 > allMaps = \cf4 ObjectFactory\cf0 .GetAllInstances<\cf4 IDomainMap\cf0 >();\par ??}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ </p>
+ <p style="margin: 0px;">
+
+ <span style="color: green;">// Retrieve all registered IDomainMap objects</span></p>
+ <p style="margin: 0px;">
+
+ <span style="color: #2b91af;">IList</span><<span style="color: #2b91af;">IDomainMap</span>>
+ allMaps = <span style="color: #2b91af;">ObjectFactory</span>.GetAllInstances<<span
+ style="color: #2b91af;">IDomainMap</span>>();</p>
+ <p style="margin: 0px;">
+ </p>
+</div>
+<!--EndFragment-->
+<p>
+ More appropriately in our code, we have a "Query" subsystem that also uses the
+ IDomainMap objects for its metadata. We have a class called
+ EntityQueryRepository that "knows" how each Domain Model class is queried.
+ When the EntityQueryRepository object is created, it takes in an array of
+ IDomainMap objects.</p>
+<!--
+{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green128\blue0;\red0\green0\blue255;\red43\green145\blue175;}??\fs20 \cf3 // Unless explicitly configured otherwise, when StructureMap\par ??\cf0 \cf3 // sees a constructor or setter argument that is an array,\par ??\cf0 \cf3 // it will fill this argument with all of the instances\par ??\cf0 \cf3 // of the argument type -- in this case, all the registered\par ??\cf0 \cf3 // IDomainMap objects\par ??\cf0 \cf4 public\cf0 EntityQueryRegistry(\cf5 IDomainMap\cf0 [] maps)\par ?? \{\par ?? maps.Each(m => m.RegisterQueryModel(\cf4 this\cf0 ));\par ?? \}}
+-->
+<div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;">
+ <p style="margin: 0px;">
+ <span style="color: green;">// Unless
+ explicitly configured otherwise, when StructureMap</span></p>
+ <p style="margin: 0px;">
+ <span style="color: green;">// sees a
+ constructor or setter argument that is an array,</span></p>
+ <p style="margin: 0px;">
+ <span style="color: green;">// it will fill
+ this argument with all of the instances</span></p>
+ <p style="margin: 0px;">
+ <span style="color: green;">// of the
+ argument type -- in this case, all the registered</span></p>
+ <p style="margin: 0px;">
+ <span style="color: green;">// IDomainMap
+ objects</span></p>
+ <p style="margin: 0px;">
+ <span style="color: blue;">public</span>
+ EntityQueryRegistry(<span style="color: #2b91af;">IDomainMap</span>[] maps)</p>
+ <p style="margin: 0px;">
+ {</p>
+ <p style="margin: 0px;">
+ maps.Each(m =>
+ m.RegisterQueryModel(<span style="color: blue;">this</span>));</p>
+ <p style="margin...
[truncated message content] |