From: <jer...@us...> - 2009-01-11 21:16:22
|
Revision: 218 http://structuremap.svn.sourceforge.net/structuremap/?rev=218&view=rev Author: jeremydmiller Date: 2009-01-11 21:16:13 +0000 (Sun, 11 Jan 2009) Log Message: ----------- documentation update and BuildUp fix Modified Paths: -------------- trunk/Source/HTML/ConstructorAndSetterInjection.htm trunk/Source/StructureMap/BuildSession.cs trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs trunk/Source/StructureMap/Configuration/DSL/Expressions/GenericFamilyExpression.cs trunk/Source/StructureMap/Configuration/DSL/Registry.cs trunk/Source/StructureMap/Configuration/DSL/SetterConvention.cs trunk/Source/StructureMap/ConfigurationExpression.cs trunk/Source/StructureMap/Diagnostics/WhatDoIHaveWriter.cs trunk/Source/StructureMap/Graph/FindAllTypesFilter.cs trunk/Source/StructureMap/Interceptors/CompoundInterceptor.cs trunk/Source/StructureMap/Interceptors/EnrichmentInterceptor.cs trunk/Source/StructureMap/Interceptors/FilteredInstanceInterceptor.cs trunk/Source/StructureMap/Interceptors/InstanceInterceptor.cs trunk/Source/StructureMap/Interceptors/Interceptors.cs trunk/Source/StructureMap/Interceptors/MatchedTypeInterceptor.cs trunk/Source/StructureMap/Interceptors/NulloInterceptor.cs trunk/Source/StructureMap/Interceptors/StartupInterceptor.cs trunk/Source/StructureMap/Pipeline/ConfiguredInstance.Expressions.cs trunk/Source/StructureMap/Pipeline/Instance.cs trunk/Source/StructureMap/Pipeline/SmartInstance.cs trunk/Source/StructureMap/StructureMapConfiguration.cs trunk/Source/StructureMap/TypeExtensions.cs trunk/Source/StructureMap.Testing/Configuration/DSL/InterceptAllInstancesOfPluginTypeTester.cs trunk/Source/StructureMap.Testing/Configuration/DSL/InterceptorTesting.cs trunk/Source/StructureMap.Testing/Graph/ConventionBasedSetterInjectionTester.cs trunk/Source/StructureMap.Testing/Graph/Interceptors/CompoundInterceptorTester.cs trunk/Source/StructureMap.Testing/Graph/Interceptors/MockTypeInterceptor.cs trunk/Source/StructureMap.Testing/Pipeline/InstanceTester.cs trunk/Source/StructureMap.Testing/StructureMap.Testing.csproj trunk/Source/StructureMap.Testing/TestData/AttributeNormalized.xml trunk/Source/StructureMap.Testing/TestData/ObjectMother.config Added Paths: ----------- trunk/Source/StructureMap.Testing/Examples/Interception.cs trunk/Source/StructureMap.Testing/TestData/ProfileSample.xml Modified: trunk/Source/HTML/ConstructorAndSetterInjection.htm =================================================================== --- trunk/Source/HTML/ConstructorAndSetterInjection.htm 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/HTML/ConstructorAndSetterInjection.htm 2009-01-11 21:16:13 UTC (rev 218) @@ -265,7 +265,7 @@ --> <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;"> <p style="margin: 0px;"> - [<span style="color: #2b91af;">Test</span>]/p> + [<span style="color: #2b91af;">Test</span>] <p style="margin: 0px;"> <span style="color: blue;">public</span> <span style="color: blue;">void</span> optional_setter_injection_with_string()</p> @@ -553,18 +553,60 @@ --> <!--EndFragment--> <hr /> - <h4>Applying Setter Injection to an Existing Object (BuildUp)</h4> + <h2>Applying Setter Injection to an Existing Object (BuildUp)</h2> <p>asdf</p> <hr /> - <h4><a name="SetterPolicies"></a>Creating Policies for Setter Injection</h4> + <h2><a name="SetterPolicies"></a>Creating Policies for Setter Injection</h2> <p>New in StructureMap 2.5.2+ is the ability to create setter injection policies. What this means is that you create conventions to define which public setter - properties will be mandatory in the construction of objects. </p> + properties will be mandatory in the construction of objects. Setter + Injection policies are set with the new "SetAllProperties" method in the + Registry DSL:</p> +<!-- +{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red163\green21\blue21;\red0\green0\blue255;\red43\green145\blue175;}??\fs20 x.SetAllProperties(policy =>\par ?? \{\par ?? policy.WithAnyTypeFromNamespace(\cf3 "StructureMap.Testing.Widget3"\cf0 );\par ??\par ?? policy.Matching(prop =>\par ?? \{\par ?? \cf4 return\cf0 prop.PropertyType.CanBeCastTo(\cf4 typeof\cf0 (\cf5 IService\cf0 ))\par ?? && !prop.Name.Contains(\cf3 "Ignore"\cf0 );\par ?? \});\par ?? \});} +--> + <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;"> + <p style="margin: 0px;"> + + x.SetAllProperties(policy =></p> + <p style="margin: 0px;"> + {</p> + <p style="margin: 0px;"> + + policy.Matching(prop =></p> + <p style="margin: 0px;"> + + {</p> + <p style="margin: 0px;"> + + <span style="color: blue;">return</span> prop.PropertyType.CanBeCastTo(<span + style="color: blue;">typeof</span> (<span style="color: #2b91af;">IService</span>))</p> + <p style="margin: 0px;"> + + && !prop.Name.Contains(<span style="color: #a31515;">"Ignore"</span>);</p> + <p style="margin: 0px;"> + + });</p> + <p style="margin: 0px;"> + });</p> + </div> +<!--EndFragment--> +<p>In the end, all you're doing is telling StructureMap that any public Setter that + matches a Predicate<PropertyInfo> policy should be a mandatory Setter. You + can make multiple declarations inside the + <a href="http://martinfowler.com/dslwip/NestedClosure.html">nested closure</a> + for SetAllProperties. <b>Any additional calls to SetAllProperties() are + purely additive.</b></p> + <p>In the sections below we'll look at some helper methods inside + SetAllProperties():</p> + <hr /> <h4>Specify a Setter Policy by Property Name</h4> <p>The sample below will make all public setter properties mandatory where the property name is suffixed by "Service." The call to NameMatches() takes in - a Predicate<string> that is a test against the property name.</p> + a Predicate<string> that is a test against the property name. The + NameMatches() method just applies a Predicate<string> test against the name of a + public setter.</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 var\cf0 container = \cf3 new\cf0 \cf4 Container\cf0 (x =>\par ?? \{\par ?? x.SetAllProperties(policy =>\par ?? \{\par ?? policy.NameMatches(name => name.EndsWith(\cf5 "Name"\cf0 ));\par ?? \});\par ?? \});} --> @@ -591,8 +633,36 @@ <!--EndFragment--> <hr /> <h4>Specify a Setter Policy by Property Type</h4> - <p> </p> + <p>Setter injection policies can also be defined by a simple test against the + PropertyInfo.PropertyType. Here's the shorthand method:</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 var\cf0 container = \cf3 new\cf0 \cf4 Container\cf0 (x =>\par ?? \{\par ?? x.ForRequestedType<\cf4 IService\cf0 >().TheDefault.Is.Object(theService);\par ?? x.ForRequestedType<\cf4 IGateway\cf0 >().TheDefaultIsConcreteType<\cf4 DefaultGateway\cf0 >();\par ??\par ?? x.SetAllProperties(policy =>\par ?? \{\par ?? policy.TypeMatches(type => type == \cf3 typeof\cf0 (\cf4 IService\cf0 ));\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;"> + var</span> container = <span style="color: blue;">new</span> + <span style="color: #2b91af;">Container</span>(x =></p> + <p style="margin: 0px;"> + {</p> + <p style="margin: 0px;"> + + x.SetAllProperties(policy =></p> + <p style="margin: 0px;"> + {</p> + <p style="margin: 0px;"> + + policy.TypeMatches(type => type == <span style="color: blue;">typeof</span> (<span + style="color: #2b91af;">IService</span>));</p> + <p style="margin: 0px;"> + });</p> + <p style="margin: 0px;"> + });</p> + </div> +<!--EndFragment--> +<p>The "OfType<T>" method is shorthand for: policy.Matching( property => + typeof(T).IsAssignableTo(property.PropertyInfo) )</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 var\cf0 container = \cf3 new\cf0 \cf4 Container\cf0 (x =>\par ?? \{\par ?? x.SetAllProperties(policy =>\par ?? \{\par ?? policy.OfType<\cf3 string\cf0 >();\par ?? policy.OfType<\cf4 IGateway\cf0 >();\par ?? \});\par ?? \});} --> <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border: black thin solid;"> @@ -619,7 +689,10 @@ });</p> </div> <!--EndFragment--> -<p> </p> +<p>You can also specify that all setter dependencies where the property type is + inside a namespace should be a mandatory setter (this check holds true for + subfolders of a namespace). This can be handy if you place all services in + a well known namespace.</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 var\cf0 container = \cf3 new\cf0 \cf4 Container\cf0 (x =>\par ?? \{\par ?? x.SetAllProperties(policy =>\par ?? \{\par ?? policy.WithAnyTypeFromNamespaceContainingType<\cf4 ClassWithNamedProperties\cf0 >();\par ?? \});\par ?? \});} --> @@ -644,7 +717,7 @@ });</p> </div> <!--EndFragment--> -<p> </p> +<p>Here's another way to specify the namespace:</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 var\cf0 container = \cf3 new\cf0 \cf4 Container\cf0 (x =>\par ?? \{\par ?? x.SetAllProperties(policy =>\par ?? \{\par ?? policy.WithAnyTypeFromNamespace(\cf5 "StructureMap.Testing.Widget3"\cf0 );\par ?? \});\par ?? \});} --> @@ -669,12 +742,9 @@ });</p> </div> <!--EndFragment--> -<p> </p> - <p> </p> +<hr /> - <hr /> - - <h4>Defining Setter Properties with Attributes</h4><p>Just use the [StructureMap.Attributes.SetterProperty] to denote properties that + <h2>Defining Setter Properties with Attributes</h2><p>Just use the [StructureMap.Attributes.SetterProperty] to denote properties that need to be filled by StructureMap. Marking a property with the [SetterProperty] makes the setter mandatory. StructureMap will throw an exception if the "ShouldCache" property isn't specified for the concrete type @@ -737,7 +807,7 @@ </div> <!--EndFragment--> <hr /> - <h4>Defining Setter Properties in Xml</h4> + <h2>Defining Setter Properties in Xml</h2> <p>Setter properties can be defined in the Xml configuration by explicitly directing StructureMap to use setter properties while building a concrete type. In the Xml, Setter configuration is done with the exact syntax as constructor Modified: trunk/Source/StructureMap/BuildSession.cs =================================================================== --- trunk/Source/StructureMap/BuildSession.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/BuildSession.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -174,7 +174,7 @@ public virtual object ApplyInterception(Type pluginType, object actualValue) { if (actualValue == null) return null; - return _interceptorLibrary.FindInterceptor(actualValue.GetType()).Process(actualValue); + return _interceptorLibrary.FindInterceptor(actualValue.GetType()).Process(actualValue, this); } public virtual void RegisterDefault(Type pluginType, object defaultObject) Modified: trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Configuration/DSL/Expressions/CreatePluginFamilyExpression.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -142,14 +142,56 @@ return target; }; - var interceptor = new PluginTypeInterceptor(typeof (PLUGINTYPE), function); + var interceptor = new PluginTypeInterceptor(typeof (PLUGINTYPE), (c, o) => + { + handler((PLUGINTYPE) o); + return o; + }); + graph.InterceptorLibrary.AddInterceptor(interceptor); }); return this; } + public CreatePluginFamilyExpression<PLUGINTYPE> InterceptWith(InstanceInterceptor interceptor) + { + _children.Add( + graph => + { + var typeInterceptor = new PluginTypeInterceptor(typeof(PLUGINTYPE), (c, o) => interceptor.Process(o, c)); + graph.InterceptorLibrary.AddInterceptor(typeInterceptor); + }); + + return this; + } + /// <summary> + /// Register an Action to run against any object of this PluginType immediately after + /// it is created, but before the new object is passed back to the caller + /// </summary> + /// <param name="handler"></param> + /// <returns></returns> + public CreatePluginFamilyExpression<PLUGINTYPE> OnCreation(Action<IContext, PLUGINTYPE> handler) + { + _children.Add( + graph => + { + Func<IContext, object, object> function = (c, o) => + { + handler(c, (PLUGINTYPE)o); + return o; + }; + + var interceptor = new PluginTypeInterceptor(typeof(PLUGINTYPE), function); + + graph.InterceptorLibrary.AddInterceptor(interceptor); + }); + + return this; + } + + /// <summary> /// Register a Func to run against any object of this PluginType immediately after it is created, /// but before the new object is passed back to the caller. Unlike <see cref="OnCreation">OnCreation()</see>, /// EnrichWith() gives the the ability to return a different object. Use this method for runtime AOP @@ -162,7 +204,7 @@ _children.Add( graph => { - Func<object, object> function = target => handler((PLUGINTYPE) target); + Func<IContext, object, object> function = (context, target) => handler((PLUGINTYPE) target); var interceptor = new PluginTypeInterceptor(typeof (PLUGINTYPE), function); graph.InterceptorLibrary.AddInterceptor(interceptor); @@ -172,6 +214,26 @@ } /// <summary> + /// Register a Func to run against any object of this PluginType immediately after it is created, + /// but before the new object is passed back to the caller. Unlike <see cref="OnCreation">OnCreation()</see>, + /// EnrichWith() gives the the ability to return a different object. Use this method for runtime AOP + /// scenarios or to return a decorator. + /// </summary> + /// <param name="handler"></param> + /// <returns></returns> + public CreatePluginFamilyExpression<PLUGINTYPE> EnrichWith(ContextEnrichmentHandler<PLUGINTYPE> handler) + { + _children.Add( + graph => + { + var interceptor = new PluginTypeInterceptor(typeof(PLUGINTYPE), (c, o) => handler(c, (PLUGINTYPE)o)); + graph.InterceptorLibrary.AddInterceptor(interceptor); + }); + + return this; + } + + /// <summary> /// Shortcut method to add an additional Instance to this Plugin Type /// as just a Concrete Type. This will only work if the Concrete Type /// has no primitive constructor or mandatory Setter arguments. @@ -209,6 +271,19 @@ } /// <summary> + /// Registers an IBuildInterceptor for this Plugin Type that executes before + /// any object of this PluginType is created. IBuildInterceptor's can be + /// used to create a custom scope + /// </summary> + /// <param name="interceptor"></param> + /// <returns></returns> + public CreatePluginFamilyExpression<PLUGINTYPE> BuildPolicyIs(IBuildInterceptor interceptor) + { + _alterations.Add(family => family.AddInterceptor(interceptor)); + return this; + } + + /// <summary> /// Largely deprecated and unnecessary with the ability to add Xml configuration files /// </summary> /// <param name="source"></param> Modified: trunk/Source/StructureMap/Configuration/DSL/Expressions/GenericFamilyExpression.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/Expressions/GenericFamilyExpression.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Configuration/DSL/Expressions/GenericFamilyExpression.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -113,6 +113,25 @@ { _registry.addExpression(graph => { + var interceptor = new PluginTypeInterceptor(_pluginType, (c, o) => func(o)); + graph.InterceptorLibrary.AddInterceptor(interceptor); + }); + + return this; + } + + /// <summary> + /// Register a Func to run against any object of this PluginType immediately after it is created, + /// but before the new object is passed back to the caller. Unlike <see cref="OnCreation">OnCreation()</see>, + /// EnrichWith() gives the the ability to return a different object. Use this method for runtime AOP + /// scenarios or to return a decorator. + /// </summary> + /// <param name="func"></param> + /// <returns></returns> + public GenericFamilyExpression EnrichWith(Func<IContext, object, object> func) + { + _registry.addExpression(graph => + { var interceptor = new PluginTypeInterceptor(_pluginType, func); graph.InterceptorLibrary.AddInterceptor(interceptor); }); Modified: trunk/Source/StructureMap/Configuration/DSL/Registry.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/Registry.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Configuration/DSL/Registry.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq.Expressions; using StructureMap.Configuration.DSL.Expressions; using StructureMap.Graph; using StructureMap.Interceptors; @@ -36,6 +37,14 @@ // Controlling Setter Injection Behavior CreatePluginFamilyExpression<PLUGINTYPE> FillAllPropertiesOfType<PLUGINTYPE>(); void SetAllProperties(Action<SetterConvention> action); + + /// <summary> + /// Use to programmatically select the constructor function of a concrete + /// class. Applies globally to all Containers in a single AppDomain. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="func"></param> + void SelectConstructor<T>(Expression<Func<T>> expression); } /// <summary> @@ -337,5 +346,16 @@ { action(new SetterConvention()); } + + /// <summary> + /// Use to programmatically select the constructor function of a concrete + /// class. Applies globally to all Containers in a single AppDomain. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="func"></param> + public void SelectConstructor<T>(Expression<Func<T>> expression) + { + PluginCache.GetPlugin(typeof(T)).UseConstructor(expression); + } } } \ No newline at end of file Modified: trunk/Source/StructureMap/Configuration/DSL/SetterConvention.cs =================================================================== --- trunk/Source/StructureMap/Configuration/DSL/SetterConvention.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Configuration/DSL/SetterConvention.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -19,6 +19,17 @@ { Matching(prop => prop.PropertyType == typeof (T)); } + + /// <summary> + /// Directs StructureMap to tread all public setters with + /// a PropertyType that matches the predicate as a + /// mandatory setter + /// </summary> + /// <param name="predicate"></param> + public void TypeMatches(Predicate<Type> predicate) + { + Matching(prop => predicate(prop.PropertyType)); + } /// <summary> /// Directs StructureMap to treat all public setters that match the Modified: trunk/Source/StructureMap/ConfigurationExpression.cs =================================================================== --- trunk/Source/StructureMap/ConfigurationExpression.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/ConfigurationExpression.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -86,16 +86,7 @@ return builder.Build(); } - /// <summary> - /// Use to programmatically select the constructor function of a concrete - /// class. Applies globally to all Containers in a single AppDomain. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="func"></param> - public void SelectConstructor<T>(Expression<Func<T>> expression) - { - PluginCache.GetPlugin(typeof (T)).UseConstructor(expression); - } + } Modified: trunk/Source/StructureMap/Diagnostics/WhatDoIHaveWriter.cs =================================================================== --- trunk/Source/StructureMap/Diagnostics/WhatDoIHaveWriter.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Diagnostics/WhatDoIHaveWriter.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -67,7 +67,7 @@ _writer.AddDivider('-'); var contents = new[] { - pluginType.PluginType.AssemblyQualifiedName ?? pluginType.PluginType.Name, + "{0} ({1})".ToFormat(pluginType.PluginType.GetName(), pluginType.PluginType.GetFullName()), string.Empty, string.Empty }; Modified: trunk/Source/StructureMap/Graph/FindAllTypesFilter.cs =================================================================== --- trunk/Source/StructureMap/Graph/FindAllTypesFilter.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Graph/FindAllTypesFilter.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -5,7 +5,7 @@ public class FindAllTypesFilter : TypeRules, ITypeScanner { private readonly Type _pluginType; - private Func<Type, string> _getName = type => type.FullName; + private Func<Type, string> _getName = type => PluginCache.GetPlugin(type).ConcreteKey; public FindAllTypesFilter(Type pluginType) { Modified: trunk/Source/StructureMap/Interceptors/CompoundInterceptor.cs =================================================================== --- trunk/Source/StructureMap/Interceptors/CompoundInterceptor.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Interceptors/CompoundInterceptor.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -17,12 +17,12 @@ #region InstanceInterceptor Members - public object Process(object target) + public object Process(object target, IContext context) { object returnValue = target; foreach (InstanceInterceptor interceptor in _interceptors) { - returnValue = interceptor.Process(returnValue); + returnValue = interceptor.Process(returnValue, context); } return returnValue; Modified: trunk/Source/StructureMap/Interceptors/EnrichmentInterceptor.cs =================================================================== --- trunk/Source/StructureMap/Interceptors/EnrichmentInterceptor.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Interceptors/EnrichmentInterceptor.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -1,20 +1,21 @@ namespace StructureMap.Interceptors { + // TODO -- gotta change to use IContext public class EnrichmentInterceptor<T> : InstanceInterceptor { - private readonly EnrichmentHandler<T> _handler; + private readonly ContextEnrichmentHandler<T> _handler; - public EnrichmentInterceptor(EnrichmentHandler<T> handler) + public EnrichmentInterceptor(ContextEnrichmentHandler<T> handler) { _handler = handler; } #region InstanceInterceptor Members - public object Process(object target) + public object Process(object target, IContext context) { - return _handler((T) target); + return _handler(context, (T) target); } #endregion Modified: trunk/Source/StructureMap/Interceptors/FilteredInstanceInterceptor.cs =================================================================== --- trunk/Source/StructureMap/Interceptors/FilteredInstanceInterceptor.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Interceptors/FilteredInstanceInterceptor.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -22,10 +22,10 @@ /// </summary> public class PluginTypeInterceptor : TypeInterceptor { - private readonly Func<object, object> _function; + private readonly Func<IContext, object, object> _function; private readonly Type _pluginType; - public PluginTypeInterceptor(Type pluginType, Func<object, object> function) + public PluginTypeInterceptor(Type pluginType, Func<IContext, object, object> function) { _pluginType = pluginType; _function = function; @@ -38,9 +38,9 @@ return TypeRules.CanBeCast(_pluginType, type); } - public object Process(object target) + public object Process(object target, IContext context) { - return _function(target); + return _function(context, target); } #endregion Modified: trunk/Source/StructureMap/Interceptors/InstanceInterceptor.cs =================================================================== --- trunk/Source/StructureMap/Interceptors/InstanceInterceptor.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Interceptors/InstanceInterceptor.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -8,6 +8,6 @@ /// </summary> public interface InstanceInterceptor { - object Process(object target); + object Process(object target, IContext context); } } \ No newline at end of file Modified: trunk/Source/StructureMap/Interceptors/Interceptors.cs =================================================================== --- trunk/Source/StructureMap/Interceptors/Interceptors.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Interceptors/Interceptors.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -1,4 +1,5 @@ namespace StructureMap.Interceptors { public delegate object EnrichmentHandler<T>(T target); + public delegate object ContextEnrichmentHandler<T>(IContext context, T target); } \ No newline at end of file Modified: trunk/Source/StructureMap/Interceptors/MatchedTypeInterceptor.cs =================================================================== --- trunk/Source/StructureMap/Interceptors/MatchedTypeInterceptor.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Interceptors/MatchedTypeInterceptor.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -5,9 +5,9 @@ public class MatchedTypeInterceptor : TypeInterceptor { private readonly Predicate<Type> _match; - private Func<object, object> _interception; + private Func<IContext, object, object> _interception; - internal MatchedTypeInterceptor(Predicate<Type> match) + public MatchedTypeInterceptor(Predicate<Type> match) { _match = match; } @@ -19,16 +19,32 @@ return _match(type); } - public object Process(object target) + public object Process(object target, IContext context) { - return _interception(target); + return _interception(context, target); } #endregion + /// <summary> + /// Specify how objects matching the Type predicate + /// will be intercepted + /// </summary> + /// <param name="interception"></param> public void InterceptWith(Func<object, object> interception) { + _interception = (context, o) => interception(o); + } + + /// <summary> + /// Specify how objects matching the Type predicate + /// will be intercepted + /// </summary> + /// <param name="interception"></param> + public void InterceptWith(Func<IContext, object, object> interception) + { _interception = interception; } + } } \ No newline at end of file Modified: trunk/Source/StructureMap/Interceptors/NulloInterceptor.cs =================================================================== --- trunk/Source/StructureMap/Interceptors/NulloInterceptor.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Interceptors/NulloInterceptor.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -4,7 +4,7 @@ { #region InstanceInterceptor Members - public object Process(object target) + public object Process(object target, IContext context) { return target; } Modified: trunk/Source/StructureMap/Interceptors/StartupInterceptor.cs =================================================================== --- trunk/Source/StructureMap/Interceptors/StartupInterceptor.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Interceptors/StartupInterceptor.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -4,18 +4,18 @@ { public class StartupInterceptor<T> : InstanceInterceptor { - private readonly Action<T> _handler; + private readonly Action<IContext, T> _handler; - public StartupInterceptor(Action<T> handler) + public StartupInterceptor(Action<IContext, T> handler) { _handler = handler; } #region InstanceInterceptor Members - public object Process(object target) + public object Process(object target, IContext context) { - _handler((T) target); + _handler(context, (T) target); return target; } Modified: trunk/Source/StructureMap/Pipeline/ConfiguredInstance.Expressions.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/ConfiguredInstance.Expressions.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Pipeline/ConfiguredInstance.Expressions.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -21,6 +21,21 @@ /// <returns></returns> public ConfiguredInstance OnCreation<TYPE>(Action<TYPE> handler) { + var interceptor = new StartupInterceptor<TYPE>((c, o) => handler(o)); + Interceptor = interceptor; + + return this; + } + + /// <summary> + /// Register an Action to perform on the object created by this Instance + /// before it is returned to the caller + /// </summary> + /// <typeparam name="TYPE"></typeparam> + /// <param name="handler"></param> + /// <returns></returns> + public ConfiguredInstance OnCreation<TYPE>(Action<IContext, TYPE> handler) + { var interceptor = new StartupInterceptor<TYPE>(handler); Interceptor = interceptor; @@ -35,6 +50,20 @@ /// <returns></returns> public ConfiguredInstance EnrichWith<TYPE>(EnrichmentHandler<TYPE> handler) { + var interceptor = new EnrichmentInterceptor<TYPE>((c, o) => handler(o)); + Interceptor = interceptor; + + return this; + } + + /// <summary> + /// Register a Func to potentially enrich or substitute for the object + /// created by this Instance before it is returned to the caller + /// </summary> + /// <param name="handler"></param> + /// <returns></returns> + public ConfiguredInstance EnrichWith<TYPE>(ContextEnrichmentHandler<TYPE> handler) + { var interceptor = new EnrichmentInterceptor<TYPE>(handler); Interceptor = interceptor; Modified: trunk/Source/StructureMap/Pipeline/Instance.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/Instance.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Pipeline/Instance.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -106,7 +106,7 @@ // Allow the Interceptor a chance to enhance, configure, // wrap with a decorator, or even replace the rawValue - object finalValue = applyInterception(rawValue, pluginType); + object finalValue = applyInterception(rawValue, pluginType, session); markBuildStackFinish(session); @@ -172,12 +172,12 @@ } - private object applyInterception(object rawValue, Type pluginType) + private object applyInterception(object rawValue, Type pluginType, IContext context) { try { // Intercept with the Instance-specific InstanceInterceptor - return _interceptor.Process(rawValue); + return _interceptor.Process(rawValue, context); } catch (Exception e) { @@ -234,7 +234,7 @@ /// <returns></returns> public T OnCreation<TYPE>(Action<TYPE> handler) { - var interceptor = new StartupInterceptor<TYPE>(handler); + var interceptor = new StartupInterceptor<TYPE>((c, o) => handler(o)); Interceptor = interceptor; return thisInstance; @@ -249,6 +249,21 @@ /// <returns></returns> public T EnrichWith<TYPE>(EnrichmentHandler<TYPE> handler) { + var interceptor = new EnrichmentInterceptor<TYPE>((c, o) => handler(o)); + Interceptor = interceptor; + + return thisInstance; + } + + /// <summary> + /// Register a Func to potentially enrich or substitute for the object + /// created by this Instance before it is returned to the caller + /// </summary> + /// <typeparam name="TYPE"></typeparam> + /// <param name="handler"></param> + /// <returns></returns> + public T EnrichWith<TYPE>(ContextEnrichmentHandler<TYPE> handler) + { var interceptor = new EnrichmentInterceptor<TYPE>(handler); Interceptor = interceptor; Modified: trunk/Source/StructureMap/Pipeline/SmartInstance.cs =================================================================== --- trunk/Source/StructureMap/Pipeline/SmartInstance.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/Pipeline/SmartInstance.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -39,6 +39,21 @@ /// <returns></returns> public SmartInstance<T> OnCreation(Action<T> handler) { + var interceptor = new StartupInterceptor<T>((c, o) => handler(o)); + Interceptor = interceptor; + + return this; + } + + /// <summary> + /// Register an Action to perform on the object created by this Instance + /// before it is returned to the caller + /// </summary> + /// <typeparam name="T"></typeparam> + /// <param name="handler"></param> + /// <returns></returns> + public SmartInstance<T> OnCreation(Action<IContext, T> handler) + { var interceptor = new StartupInterceptor<T>(handler); Interceptor = interceptor; @@ -53,7 +68,7 @@ /// <returns></returns> public SmartInstance<T> EnrichWith(EnrichmentHandler<T> handler) { - var interceptor = new EnrichmentInterceptor<T>(handler); + var interceptor = new EnrichmentInterceptor<T>((c, o) => handler(o)); Interceptor = interceptor; return this; @@ -67,6 +82,34 @@ /// <returns></returns> public SmartInstance<T> EnrichWith<PLUGINTYPE>(EnrichmentHandler<PLUGINTYPE> handler) { + var interceptor = new EnrichmentInterceptor<PLUGINTYPE>((c, o) => handler(o)); + Interceptor = interceptor; + + return this; + } + + /// <summary> + /// Register a Func to potentially enrich or substitute for the object + /// created by this Instance before it is returned to the caller + /// </summary> + /// <param name="handler"></param> + /// <returns></returns> + public SmartInstance<T> EnrichWith(ContextEnrichmentHandler<T> handler) + { + var interceptor = new EnrichmentInterceptor<T>(handler); + Interceptor = interceptor; + + return this; + } + + /// <summary> + /// Register a Func to potentially enrich or substitute for the object + /// created by this Instance before it is returned to the caller + /// </summary> + /// <param name="handler"></param> + /// <returns></returns> + public SmartInstance<T> EnrichWith<PLUGINTYPE>(ContextEnrichmentHandler<PLUGINTYPE> handler) + { var interceptor = new EnrichmentInterceptor<PLUGINTYPE>(handler); Interceptor = interceptor; Modified: trunk/Source/StructureMap/StructureMapConfiguration.cs =================================================================== --- trunk/Source/StructureMap/StructureMapConfiguration.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/StructureMapConfiguration.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -103,8 +103,6 @@ /// </summary> public static void ResetAll() { - PluginCache.ResetAll(); - _sealed = false; _log = new GraphLog(); @@ -115,7 +113,6 @@ UseDefaultStructureMapConfigFile = false; IgnoreStructureMapConfig = false; - PluginCache.ResetAll(); ObjectFactory.Reset(); } Modified: trunk/Source/StructureMap/TypeExtensions.cs =================================================================== --- trunk/Source/StructureMap/TypeExtensions.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap/TypeExtensions.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -67,5 +67,29 @@ return null; } + public static string GetName(this Type type) + { + if (type.IsGenericType) + { + string[] parameters = Array.ConvertAll(type.GetGenericArguments(), t => t.GetName()); + var parameterList = string.Join(", ", parameters); + return "{0}<{1}>".ToFormat(type.Name, parameterList); + } + + return type.Name; + } + + public static string GetFullName(this Type type) + { + if (type.IsGenericType) + { + string[] parameters = Array.ConvertAll(type.GetGenericArguments(), t => t.GetName()); + var parameterList = string.Join(", ", parameters); + return "{0}<{1}>".ToFormat(type.Name, parameterList); + } + + return type.FullName; + } + } } \ No newline at end of file Modified: trunk/Source/StructureMap.Testing/Configuration/DSL/InterceptAllInstancesOfPluginTypeTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Configuration/DSL/InterceptAllInstancesOfPluginTypeTester.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap.Testing/Configuration/DSL/InterceptAllInstancesOfPluginTypeTester.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -1,6 +1,7 @@ using System; using NUnit.Framework; using StructureMap.Configuration.DSL; +using StructureMap.Interceptors; using StructureMap.Testing.Widget3; namespace StructureMap.Testing.Configuration.DSL @@ -79,12 +80,39 @@ } [Test] + public void custom_interceptor_for_all() + { + var interceptor = new MockInterceptor(); + IService service = getService("Green", r => + { + r.ForRequestedType<IService>().InterceptWith(interceptor) + .AddInstances(x => { x.ConstructedBy(() => new ColorService("Green")).WithName("Green"); }); + }); + + interceptor.Target.ShouldBeTheSameAs(service); + } + + public class MockInterceptor : InstanceInterceptor + { + public object Process(object target, IContext context) + { + Target = target; + return target; + } + + public object Target { get; set; } + } + + [Test] public void OnStartupForAll() { - Action<Registry> action = r => + Action<Registry> action = registry => { - r.ForRequestedType<IService>().OnCreation(s => _lastService = s) - .AddInstances(x => { x.ConstructedBy(() => new ColorService("Green")).WithName("Green"); }); + registry.ForRequestedType<IService>().OnCreation(s => _lastService = s) + .AddInstances(x => + { + x.ConstructedBy(() => new ColorService("Green")).WithName("Green"); + }); }; Modified: trunk/Source/StructureMap.Testing/Configuration/DSL/InterceptorTesting.cs =================================================================== --- trunk/Source/StructureMap.Testing/Configuration/DSL/InterceptorTesting.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap.Testing/Configuration/DSL/InterceptorTesting.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -14,31 +14,50 @@ public void SetUp() { _lastService = null; + recorder = new ContextRecorder(); - _container = new Container(r => r.ForRequestedType<IService>().AddInstances(x => + _container = new Container(r => { - x.OfConcreteType<ColorService>() - .OnCreation(s => _lastService = s) - .WithName("Intercepted") - .WithCtorArg("color").EqualTo("Red"); + r.ForRequestedType<ContextRecorder>().TheDefault.IsThis(recorder); - x.OfConcreteType<ColorService>() - .WithName("NotIntercepted") - .WithCtorArg("color").EqualTo("Blue"); + r.ForRequestedType<IService>().AddInstances(x => + { + x.OfConcreteType<ColorService>() + .OnCreation(s => _lastService = s) + .WithName("Intercepted") + .WithCtorArg("color").EqualTo("Red"); - x.Object(new ColorService("Yellow")) - .WithName("Yellow") - .OnCreation<ColorService>(s => _lastService = s); + x.OfConcreteType<ColorService>() + .OnCreation((c, s) => c.GetInstance<ContextRecorder>().WasTouched = true) + .WithName("InterceptedWithContext") + .WithCtorArg("color").EqualTo("Red"); - x.ConstructedBy(() => new ColorService("Purple")).WithName("Purple") - .EnrichWith<IService>(s => new DecoratorService(s)); + x.OfConcreteType<ColorService>() + .WithName("NotIntercepted") + .WithCtorArg("color").EqualTo("Blue"); - x.OfConcreteType<ColorService>().WithName("Decorated").EnrichWith<IService>(s => new DecoratorService(s)) - .WithCtorArg("color").EqualTo("Orange"); + x.Object(new ColorService("Yellow")) + .WithName("Yellow") + .OnCreation<ColorService>(s => _lastService = s); - x.Object(new ColorService("Yellow")).WithName("Bad") - .OnCreation<ColorService>(obj => { throw new ApplicationException("Bad!"); }); - })); + x.ConstructedBy(() => new ColorService("Purple")).WithName("Purple") + .EnrichWith<IService>(s => new DecoratorService(s)); + + x.ConstructedBy(() => new ColorService("Purple")).WithName("DecoratedWithContext") + .EnrichWith<IService>((c, s) => + { + c.GetInstance<ContextRecorder>().WasTouched = true; + return new DecoratorService(s); + }); + + x.OfConcreteType<ColorService>().WithName("Decorated").EnrichWith<IService>( + s => new DecoratorService(s)) + .WithCtorArg("color").EqualTo("Orange"); + + x.Object(new ColorService("Yellow")).WithName("Bad") + .OnCreation<ColorService>(obj => { throw new ApplicationException("Bad!"); }); + }); + }); } #endregion @@ -46,8 +65,23 @@ private ColorService _lastService; private IContainer _container; + private ContextRecorder recorder; [Test] + public void call_the_build_context_with_startup() + { + _container.GetInstance<IService>("InterceptedWithContext"); + recorder.WasTouched.ShouldBeTrue(); + } + + [Test] + public void call_the_build_context_with_enrich() + { + _container.GetInstance<IService>("DecoratedWithContext"); + recorder.WasTouched.ShouldBeTrue(); + } + + [Test] public void DecorateAConstructedService() { var service = _container.GetInstance<IService>("Purple"); @@ -120,4 +154,9 @@ get { return _inner; } } } + + public class ContextRecorder + { + public bool WasTouched { get; set; } + } } \ No newline at end of file Added: trunk/Source/StructureMap.Testing/Examples/Interception.cs =================================================================== --- trunk/Source/StructureMap.Testing/Examples/Interception.cs (rev 0) +++ trunk/Source/StructureMap.Testing/Examples/Interception.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices.ComTypes; +using System.Text; +using NUnit.Framework; +using StructureMap.Configuration.DSL; +using StructureMap.Interceptors; +using StructureMap; + +namespace StructureMap.Testing.Examples +{ + public interface IConnectionListener + { + void StartConnection(); + } + + public class ClassThatNeedsSomeBootstrapping : IConnectionListener + { + public void Start() + { + + } + + public void Connect(IConnectionPoint connection) + { + + } + + public void StartConnection() + { + throw new NotImplementedException(); + } + } + + public class LoggingDecorator : IConnectionListener + { + private readonly IConnectionListener _inner; + + public LoggingDecorator(IConnectionListener inner) + { + _inner = inner; + } + + public IConnectionListener Inner + { + get { return _inner; } + } + + public void StartConnection() + { + + } + } + + public class InterceptionRegistry : Registry + { + public InterceptionRegistry() + { + // Perform an Action<T> upon the object of type T + // just created before it is returned to the caller + ForRequestedType<ClassThatNeedsSomeBootstrapping>().TheDefault.Is + .OfConcreteType<ClassThatNeedsSomeBootstrapping>() + .OnCreation(x => x.Start()); + + // or... + + // You can also register an Action<IContext, T> to get access + // to all the services and capabilities of the BuildSession + ForRequestedType<ClassThatNeedsSomeBootstrapping>().TheDefault.Is + .OfConcreteType<ClassThatNeedsSomeBootstrapping>() + .OnCreation((context, x) => + { + var connection = context.GetInstance<IConnectionPoint>(); + x.Connect(connection); + }); + + + ForRequestedType<IConnectionListener>().TheDefault.Is + .OfConcreteType<ClassThatNeedsSomeBootstrapping>() + .EnrichWith(x => new LoggingDecorator(x)); + + ForRequestedType<IConnectionListener>().TheDefault.Is + .OfConcreteType<ClassThatNeedsSomeBootstrapping>() + .EnrichWith((context, x) => + { + var connection = context.GetInstance<IConnectionPoint>(); + x.Connect(connection); + + return new LoggingDecorator(x); + }); + + + ForRequestedType<IConnectionListener>().TheDefault.Is + .OfConcreteType<ClassThatNeedsSomeBootstrapping>() + .InterceptWith(new CustomInterceptor()); + + + + // Place the Interception at the PluginType level + ForRequestedType<IConnectionListener>() + .OnCreation(x => x.StartConnection()) // OnCreation + .EnrichWith(x => new LoggingDecorator(x)) // Enrich + .InterceptWith(new CustomInterceptor()) // Custom Interceptor + + + .TheDefaultIsConcreteType<ClassThatNeedsSomeBootstrapping>(); + + } + } + + [TestFixture, Explicit] + public class InterceptionRegistryInAction + { + [Test] + public void see_the_enrichment_with_a_decorator_in_action() + { + var container = new Container(new InterceptionRegistry()); + container.GetInstance<IConnectionListener>() + .ShouldBeOfType<LoggingDecorator>() + .Inner.ShouldBeOfType<ClassThatNeedsSomeBootstrapping>(); + } + } + + public class CustomInterceptor : InstanceInterceptor + { + public object Process(object target, IContext context) + { + // manipulate the target object and return a wrapped version + return wrapTarget(target); + } + + private object wrapTarget(object target) + { + throw new NotImplementedException(); + } + } + + + + + public interface IEventListener<T> + { + void ProcessEvent(T @event); + } + + public interface IEventAggregator + { + void RegisterListener<T>(IEventListener<T> listener); + void PublishEvent<T>(T @event); + } + + + + public class ListenerInterceptor : TypeInterceptor + { + public object Process(object target, IContext context) + { + // Assuming that "target" is an implementation of IEventListener<T>, + // we'll do a little bit of generics sleight of hand + // to register "target" with IEventAggregator + var eventType = target.GetType().FindInterfaceThatCloses(typeof (IEventListener<>)).GetGenericArguments()[0]; + var type = typeof (Registration<>).MakeGenericType(eventType); + Registration registration = (Registration) Activator.CreateInstance(type); + registration.RegisterListener(context, target); + + // we didn't change the target object, so just return it + return target; + } + + public bool MatchesType(Type type) + { + // ImplementsInterfaceTemplate is an Extension method in the + // StructureMap namespace that basically says: + // does this type implement any closed type of the open template type? + return type.ImplementsInterfaceTemplate(typeof (IEventListener<>)); + } + + // The inner type and interface is just a little trick to + // grease the generic wheels + public interface Registration + { + void RegisterListener(IContext context, object listener); + } + + public class Registration<T> : Registration + { + public void RegisterListener(IContext context, object listener) + { + var aggregator = context.GetInstance<IEventAggregator>(); + aggregator.RegisterListener<T>((IEventListener<T>) listener); + } + } + } + + public class ListeningRegistry : Registry + { + public ListeningRegistry() + { + RegisterInterceptor(new ListenerInterceptor()); + } + } +} Modified: trunk/Source/StructureMap.Testing/Graph/ConventionBasedSetterInjectionTester.cs =================================================================== --- trunk/Source/StructureMap.Testing/Graph/ConventionBasedSetterInjectionTester.cs 2009-01-08 13:28:57 UTC (rev 217) +++ trunk/Source/StructureMap.Testing/Graph/ConventionBasedSetterInjectionTester.cs 2009-01-11 21:16:13 UTC (rev 218) @@ -88,6 +88,27 @@ } [Test] + public void fill_all_properties_of_types_in_namespace_by_generic() + { + + var container = new Container(x => + { + x.SetAllProperties(policy => + { + policy.WithAnyTypeFromNamespaceContainingType<IService>(); + }); + }); + + var plugin = PluginCache.GetPlugin(typeof(ClassWithNamedProperties)); + + plugin.Setters.IsMandatory("Age").ShouldBeFalse(); + plugin.Setters.IsMandatory("FirstName").ShouldBeFalse(); + plugin.Setters.IsMandatory("LastName").ShouldBeFalse(); + plugin.Setters.IsMandatory("Gateway").ShouldBeTrue(); + plugin.Setters.IsMandatory("Service").ShouldBeTrue(); + } + + [Test] public void specify_setter_policy_and_construct_an_object() { var theService = new ColorService("red"); @@ -108,7 +129,30 @@ target.Gateway.ShouldBeOfType<DefaultGateway>(); } + [Test] + public void specify_setter_policy_by_a_predicate_on_property_type() + { + var theService = new ColorService("red"); + var container = new Container(x => + { + x.ForRequestedType<IService>().TheDefault.Is.Object(theService); + x.ForRequestedType<IGateway>().TheDefaultIsConcreteType<DefaultGateway>(); + + x.SetAllProperties(policy => + { + policy.TypeMatches(type => type == typeof (IService)); + }); + }); + + var target = container.GetInstance<ClassWithNamedProperties>(); + target.Service.ShouldBeTheSameAs(theService); + target.Gateway.ShouldBeNull(); + + + } + + public class ClassWithNamedProperties { public int Age { get; set; } Modified: trunk/Source/StructureMap.Testing/Graph/Interceptors/CompoundInterceptorTester.cs =================================================================== ---... [truncated message content] |