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] |