|
Home |
Frequently Asked Questions
How do I make StructureMap watch an Assembly for PluginFamily's and Plugin's?At this time, the only way is to place an <Assembly> node in the StructureMap.config file. StructureMap will not function correctly unless the assembly is both configured and in the binary path of the application Example Configuration<StructureMap> <Assembly Name="StructureMap.Testing.Widget"/> <Assembly Name="StructureMap.Testing.Widget2"/> <Assembly Name="StructureMap.Testing.Widget3"/> </StructureMap>Back to Top Where does the StructureMap.config file go?The StructureMap.config file should be placed in the same directory as the App.config or Web.config file. StructureMap uses the following code to find the file:
public static string GetStructureMapConfigurationPath()
{
string configPath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
configPath += "\\StructureMap.config";
configPath = configPath.Replace("\\\\", "\\");
return configPath;
}
How can I specify a PluginFamily by using custom attributes?Mark an interface or class declaration with the [StructureMap.PluginFamily] attribute. Optionally, specify the default instance key. Configuring a PluginFamily in the config file will override this attribute Example
[StructureMap.PluginFamily("Default")]
public interface IGateway
{
void DoSomething();
string WhoAmI{get;}
}
How can I configure a PluginFamily in the config file?Place a <PluginFamily> node in the StructureMap.config file. Specify the assembly and full type name of the PluginType of the PluginFamily Example<PluginFamily Type="StructureMap.Testing.Widget.IWidget" Assembly="StructureMap.Testing.Widget" DefaultKey="Red"> <Source Type="XmlFile" FilePath="FullTesting.XML" XPath="Widgets" NodeName="Widget"/> <Plugin Assembly="StructureMap.Testing.Widget" Type="StructureMap.Testing.Widget.NotPluggableWidget" ConcreteKey="NotPluggable"/> </PluginFamily> <!-- If no source is defined, use the default MementoSource --> <PluginFamily Type="StructureMap.Testing.Widget.Column" Assembly="StructureMap.Testing.Widget"> <Source Type="XmlFile" FilePath="FullTesting.XML" XPath="Columns" NodeName="Columns" /> </PluginFamily> <PluginFamily Type="StructureMap.Testing.Widget.Rule" Assembly="StructureMap.Testing.Widget" DefaultKey="Blue"> <Interceptors> <Interceptor Type="Singleton"></Interceptor> </Interceptors> <Instance Key="Red" Type="Color"> <Property Name="Color" Value="Red" /> </Instance> <Instance Key="Blue" Type="Color"> <Property Name="Color" Value="Blue" /> </Instance> <Instance Key="Bigger" Type="GreaterThan"> <Property Name="Attribute" Value="MyDad" /> <Property Name="Value" Value="10" /> </Instance> </PluginFamily> How do I specify a Plugin by using custom attributes?Use the [StructureMap.Pluggable] attribute to mark a concrete class declaration as a Plugin. The class will be added to any and all PluginFamily's that the class can be casted to. In order for the attribute to be found, the containing assembly must be included in the StructureMap.config file. The first property is the ConcreteKey of the Plugin Example
[StructureMap.Pluggable("Default", "")]
public class DefaultGateway : IGateway
{
public void DoSomething()
{
}
public string WhoAmI
{
get {return "Default";}
}
}
How do I configure a Plugin in the config file?Use a <Plugin> element nested inside a <PluginFamily> node in the StructureMap.config file. The containing assembly must also be specified Example<PluginFamily Type="StructureMap.Testing.Widget5.IGridColumn" Assembly="StructureMap.Testing.Widget5" DefaultKey=""> <!-- Plugin w/o setter injection --> <Plugin Assembly="StructureMap.Testing.Widget5" Type="StructureMap.Testing.Widget5.LinkGridColumn" ConcreteKey="Link"> <!-- Plugin with setter injection --> <Plugin Assembly="StructureMap.Testing.Widget5" Type="StructureMap.Testing.Widget5.OtherGridColumn" ConcreteKey="Other"> <Setter Name="ColumnName" /> <Setter Name="FontStyle" /> <Setter Name="Rules" /> <Setter Name="Widget" /> <Setter Name="WrapLines" /> </Plugin> </PluginFamily> How do I configure an object instance in the config file?Create an <Instance> element within the correct <PluginFamily> node in StructureMap.config. The ConcreteKey of the Plugin class to use and an identifying InstanceKey must be defined. The properties to pass into the constructor function are contained in nested <Property> elements. Example<PluginFamily Type="StructureMap.Testing.Widget4.IStrategy" Assembly="StructureMap.Testing.Widget4" DefaultKey="Red"> <Instance Key="Blue" Type="Color"> <Property Name="color" Value="Blue" /> </Instance> <Instance Key="DeepTest" Type="Complex"> <Property Name="defaultStrategy" Type="Decorator"> <Property Name="innerStrategy" Type="Decorator"> <Property Name="innerStrategy" Type="Random"> <Property Name="seed" Value="0.125"/> </Property> </Property> </Property> <Property Name="innerStrategies"> <Property Key="Red"></Property> <Property><!-- Default --></Property> <Property Type="Random"> <Property Name="seed" Value="0.034"/> </Property> <Property Type="Decorator"> <Property Name="innerStrategy" Type="Basic"> <Property Name="count" Value="10" /> <Property Name="isCalculated" Value="True" /> <Property Name="name" Value="Jeremy" /> <Property Name="quantity" Value="250000" /> <Property Name="rating" Value="0.25" /> </Property> </Property> </Property> <Property Name="name" Value="DeepTest" /> <Property Name="quantity" Value="12500" /> <Property Name="strategyType" Value="OverTheHorizon"/> </Instance> <Instance Key="Red" Type="Color"> <Property Name="color" Value="Red" /> </Instance> </PluginFamily> I have a class that has no constructor arguments or each argument type is configured in StructureMap with a default. Do I have to configure an object instance in the config file, or can I just reference it by the ConcreteKey?In this case StructureMap "knows" to build an object instance of this class whenever the ConcreteKey is passed in as the InstanceKey. In the example code below, the class DefaultGateway can be created directly as "Default" because it requires no inputs to the constructor function. SecuredGateway can be created directly as "Secured" because its only input argument is another object of type IGateway, which has a default configured in StructureMap. Example
[PluginFamily( "Default" )]
public interface IGateway
{
void DoSomething();
string WhoAmI { get; }
}
[Pluggable("Default", "")]
public class DefaultGateway : IGateway
{
public DefaultGateway(){}
public void DoSomething()
{
}
public string WhoAmI
{
get {return "Default";}
}
}
[Pluggable("Secured")]
public class SecuredGateway : IGateway
{
private IGateway _innerGateway;
public SecuredGateway(IGateway innerGateway)
{
_innerGateway = innerGateway;
}
public void DoSomething()
{
}
public string WhoAmI
{
get {return "Secured";}
}
}
// Fetch a DefaultGateway from ObjectFactory
IGateway gateway = (IGateway)ObjectFactory.GetNamedInstance(typeof(IGateway), "Default");
// Fetch a SecuredGateway from ObjectFactory
IGateway gateway = (IGateway)ObjectFactory.GetNamedInstance(typeof(IGateway), "Secured");
How do I specify the default object instance for a PluginFamily?There are several ways. The first way is to mark the DefaultKey property of a [PluginFamily] attribute. The second way is to set the DefaultKey attribute of a <PluginFamily> node in the config file. Either way, this value refers to a named instance for the PluginFamily. The DefaultKey can be overriden at runtime through ObjectFactory or at configuration time by using the Profile and Machine nodes in the config file. Attribute Example// The instance called "Default" will be the default object instance created by StructureMap when an IGateway is requested.
[StructureMap.PluginFamily("Default")]
public interface IGateway
{
void DoSomething();
string WhoAmI{get;}
}
Configuration Example<PluginFamily Type="StructureMap.Testing.Widget.IWidget" Assembly="StructureMap.Testing.Widget" DefaultKey="Red"> <Instance Type="Color" Key="Blue"> <Property Name="Color" Value="Blue" /> </Instance> <Instance Type="Color" Key="Green"> <Property Name="Color" Value="Green" /> </Instance> <Instance Type="NotPluggable" Key="NotPluggableInstance"></Instance> <Instance Type="Color" Key="Red"> <Property Name="Color" Value="Red" /> </Instance> </PluginFamily> Overriding at RuntimeObjectFactory.SetDefaultInstanceName(typeof(IWidget), "Green"); Which constructor function is called by StructureMap for a particular class?By default, StructureMap will use the "greediest" constructor function, i.e. the constructor function with the most arguments. The behavior can be altered by using a custom attribute as shown in the FAQ below. Can I override the constructor function called by StructureMap?Yes. In some unit testing scenarios, it may make more sense for a testing only constructor that takes in multiple arguments and a production constructor that builds default children. Use the [StructureMap.DefaultConstructor] attribute on a constructor function to override the default behavior. [StructureMap.Pluggable("Complex", "Complex rule for testing")]
public class ComplexRule : Rule
{
private string _String;
private string _String2;
private int _Int;
private long _Long;
private byte _Byte;
private double _Double;
private bool _Bool;
[DefaultConstructor]
public ComplexRule(string String, string String2, int Int, long Long, byte Byte, double Double, bool Bool)
{
this._String = String;
this._String2 = String2;
this._Int = Int;
this._Long = Long;
this._Byte = Byte;
this._Double = Double;
this._Bool = Bool;
}
public ComplexRule(string String, string String2, int Int, long Long, byte Byte, double Double, bool Bool, string extra)
{
}
}
How do I configure a non-primitive child argument to a constructor function?There are three (and a half) options. First though, the child type must be a PluginFamily controlled by StructureMap for this to work.
Example[PluginFamily]
[StructureMap.Pluggable("Default", "")]
public class GrandChild
{
private bool _RightHanded;
private int _BirthYear;
public GrandChild(bool RightHanded, int BirthYear)
{
_BirthYear = BirthYear;
_RightHanded = RightHanded;
}
public bool RightHanded
{
get {return _RightHanded;}
}
public int BirthYear
{
get {return _BirthYear;}
}
}
[StructureMap.Pluggable("Leftie", "")]
public class LeftieGrandChild : GrandChild
{
public LeftieGrandChild(int BirthYear) : base(false, BirthYear){}
}
[PluginFamily]
[StructureMap.Pluggable("Default", "")]
public class Child
{
private string _Name;
private GrandChild _MyGrandChild;
public Child(string Name, GrandChild MyGrandChild)
{
_Name = Name;
_MyGrandChild = MyGrandChild;
}
public string Name
{
get {return _Name;}
}
public GrandChild MyGrandChild
{
get {return _MyGrandChild;}
}
}
[PluginFamily]
[StructureMap.Pluggable("Default", "")]
public class Parent
{
private int _Age;
private string _EyeColor;
private Child _MyChild;
public Parent(int Age, string EyeColor, Child MyChild)
{
_Age = Age;
_EyeColor = EyeColor;
_MyChild = MyChild;
}
public int Age
{
get {return _Age;}
}
public string EyeColor
{
get {return _EyeColor;}
}
public Child MyChild
{
get {return _MyChild;}
}
}
Config Section for Parent Instances<!--
Define the Child Member by Reference to the "Marsha" object instance --> <Instance
Type="Default"
Key="Jerry">
<Property
Name="Age"
Value="72"/>
<Property
Name="EyeColor"
Value="Blue"/>
<Property
Name="MyChild"
Key="Marsha"/> </Instance> <!--
Inline configuration of the Child Member. Note
that "MyChild" is a nested InstanceMemento --> <Instance
Type="Default"
Key="Jackie">
<Property
Name="Age"
Value="70"/>
<Property
Name="EyeColor"
Value="Green"/>
<Property
Name="MyChild"
Type="Default">
<Property
Name="Name"
Value="
<Property
Name="MyGrandChild"
Type="Leftie">
<Property
Name="BirthYear"
Value="1992"/>
</Property>
</Property> </Instance> <!--
No "MyChild" member is defined, so the default Child object instance will be
used --> <Instance
Type="Default"
Key="ImplicitChild">
<Property
Name="Age"
Value="72"/>
<Property
Name="EyeColor"
Value="Blue"/> </Instance>
How do I configure an array of non-primitive objects as an argument to a constructor function?StructureMap supports a constructor argument that is an array of non-primitive objects. The child type construction must be controlled by StructureMap. The child members of the array itself are configured in the config file as embedded instances themselves within the proper <Property> element for the child member. The same rules apply for the configuration as for a single non-primitive child member. The actual node name of the array members is actually arbitrary. Any node within the <Property> element is assumed to be an array member ExampleThe Decision class below uses a collection of Rule objects in order to carry out some sort of business logic. The Rule[] array is passed into the "Rules" argument in the constructor function. public class Decision
{
public Rule[] Rules;
public Decision(Rule[] Rules)
{
this.Rules = Rules;
}
}
public abstract class Rule
{
public Rule()
{
}
public virtual bool IsTrue()
{
return true;
}
}
<Instance
Type="Default"
Key="GreenBluePurple">
<Property
Name="Rules">
<Rule
Key="Blue">
<Rule
Type="Color">
<Property
Name="Color"
Value="Blue"/>
</Rule>
<Rule
Type="Color">
<Property
Name="Color"
Value="Purple"/>
</Rule>
</Property> </Instance> How do I use the builtin Mock Injection functionality in NUnit testing?As an alternative to a pure Constructor Injection pattern for a class, it may be easier to have a child member built internally from StructureMap. StructureMap supports a runtime replacement of the normal object construction with an NMock.IMock dynamic mock object. If you only want to separate an interface from a concrete class for the purpose of easier NUnit testing, StructureMap can setup an interface/class combination for construction and mocking with only a couple of attributes ExampleWe have a gateway pattern class to some nasty old legacy system. We want to be able to mock the gateway class to unit test our code independently of the nasty legacy system. It is importatnt to call either ObjectFactory.UnMock(Type) or ObjectFactory.ResetDefaults() in the TearDown() method to un-mock the plugin type. This is a conscious design choice to ensure that unit tests are isolated and not accidentally sharing a previous NMock.IMock object from another test. [StructureMap.PluginFamily("Default")]
public interface IGateway
{
void DoSomething();
string WhoAmI{get;}
}
[StructureMap.Pluggable("Default", "")]
public class DefaultGateway : IGateway
{
#region IGateway Members
public void DoSomething()
{
// TODO: Add DefaultGateway.DoSomething implementation
}
public string WhoAmI
{
get {return "Default";}
}
#endregion
}
using NUnit.Framework;
using StructureMap;
[TestFixture]
public class MockingTester
{
private IMock _gatewayMock;
[SetUp]
public void SetUp()
{
// Set up ObjectFactory to return MockInstance's for IGateway
_gatewayMock = ObjectFactory.Mock(typeof(IGateway));
}
[TearDown]
public void TearDown()
{
// UnMock in teardown methods to avoid oddball behavior in later NUnit tests
ObjectFactory.UnMock(typeof(IGateway));
}
[Test]
public void ClassTest()
{
MyClass myClass = new MyClass();
_gatewayMock.Expect("DoSomething");
myClass.Go();
_gatewayMock.Verify();
}
}
How can I set a runtime Profile of default instances?Use a <Profile> node within the StructureMap.config file to set a related series of default overrides. The profile can be changed at runtime with a call to ObjectFactory. This feature can be useful in cases where a user interface application can run in either a connected mode or a disconnected mode. It has also been used to great effect to create different profiles for developer sandboxes versus a build machine versus a test environment. <Profile
Name="Green">
<Override
Type="StructureMap.Testing.Widget.Rule"
DefaultKey="Green"/>
<Override
Type="StructureMap.Testing.Widget.IWidget"
DefaultKey="Green"/>
</Profile>
Example CodeObjectFactory.Profile = "Stubbed"; ObjectFactory.ResetDefaults(); How can I override the default instances by Machine?The first question is why would you want to do this? For an example, the original reason for this feature was to connect each developer workstation to an individual database sandbox to avoid collisions. Simply place a <Machine> element in the config file and use <Override> elements to set the defaults for each PluginFamily, or set a Profile for the machine. It can, however, make maintenance of the config file much more difficult, so proceed with caution. Example<Machine
Name="SERVER">
<Override
Type="StructureMap.Testing.Widget.IWidget"
DefaultKey="Orange"/> </Machine> Can I use a different configuration source for object instances rather than StructureMap.config?At this point the only other alternative is a separate Xml file, but an extensibility mechanism is in place to add new types of MementoSouce's. The MementoSource for a PluginFamily can be overriden from the default by placing a <Source> node within the proper <PluginFamily> node in the config file and configuring properties like filepaths for the custom MementoSource. Possible reasons for using custom MementoSource's would be to isolate a volatile PluginFamily or to provide a centralized configuration store in a database or LDAP for a large server farm. See the configuration documentation for more information. How do I use Setter Injection?As of version 0.90 StructureMap must be explicitly configured to fill setter properties on a Plugin. StructureMap assumes that these properties are mandatory in the instance definition. If a defined setter property does not have a corresponding value set in the InstanceMemento configuration, StructureMap will throw an exception. This will probably change in a later version to allow for optional properties. The allowable CLR types for Setter Injection is the same as for Constructor Injection. Setter properties can be marked for population by either marking the properties with an attribute in the class itself, or by declaring the properties within a Plugin definition in the StructureMap.config file. Property values for Setter Injection are configured in an InstanceMemento definition no differently than constructor arguments. The [SetterProperty] attribute directs StructureMap to fill a setter property during object construction [Pluggable( "Basic" )]
public class BasicGridColumn : IGridColumn
{
private readonly string _headerText;
private IWidget _widget;
private FontStyleEnum _fontStyle;
private string _columnName;
private Rule[] _rules;
private bool _displayed;
private int _size;
private bool _wrapLines;
public BasicGridColumn( string headerText )
{
_headerText = headerText;
}
public string HeaderText
{
get { return _headerText; }
}
[SetterProperty]
public IWidget Widget
{
get { return _widget; }
set { _widget = value; }
}
[SetterProperty]
public FontStyleEnum FontStyle
{
get { return _fontStyle; }
set { _fontStyle = value; }
}
[SetterProperty]
public string ColumnName
{
get { return _columnName; }
set { _columnName = value; }
}
[SetterProperty]
public Rule[] Rules
{
get { return _rules; }
set { _rules = value; }
}
[SetterProperty]
public bool WrapLines
{
get { return _wrapLines; }
set { _wrapLines = value; }
}
public bool Displayed
{
get { return _displayed; }
set { _displayed = value; }
}
public int Size
{
get { return _size; }
set { _size = value; }
}
}
Setter properties can also be configured explicitly inside of the StructureMap.config file. This is particularly useful when using StructureMap to create class instances from external class libraries that cannot be edited with attributes. <PluginFamily Type="StructureMap.Testing.Widget5.IGridColumn" Assembly="StructureMap.Testing.Widget5" DefaultKey=""> <Plugin Assembly="StructureMap.Testing.Widget5" Type="StructureMap.Testing.Widget5.OtherGridColumn" ConcreteKey="Other"> <Setter Name="ColumnName" /> <Setter Name="FontStyle" /> <Setter Name="Rules" /> <Setter Name="Widget" /> <Setter Name="WrapLines" /> </Plugin> </PluginFamily> How do I inject a static mock or a stub in testing?In some cases it is desirable to test with either a service stub or a custom mock class created by hand. StructureMap can be instructed to at runtime to always return a testing instance for a plugin type. Any object loaded as a static mock or stub must be assignable to the plugin type, or StructureMap will throw an exception. As with the Mock Injection usage, always "un-mock" the plugin type as part of the unit test cleanup. Example[PluginFamily]
public interface IUserDataStore
{
DataSet GetData(string userName);
}
public class StubbedUserDataStore : IUserDataStore
{
private DataSet _dataSet;
public void LoadFromFile(string fileName)
{
_dataSet = new DataSet();
_dataSet.ReadXml(fileName);
}
public DataSet GetData( string userName )
{
return _dataSet;
}
}
[TestFixture]
public class SecurityTester
{
private StubbedUserDataStore _stubbedUserDataStore;
[SetUp]
public void SetUp()
{
_stubbedUserDataStore = new StubbedUserDataStore();
ObjectFactory.InjectStub(typeof(IUserDataStore), _stubbedUserDataStore);
}
[TearDown]
public void TearDown()
{
ObjectFactory.UnMock(typeof(IUserDataStore));
}
[Test]
public void Test1()
{
// Set up known test data
_stubbedUserDataStore.LoadFromFile("Test1.xml");
/* Test implementations */
}
}
How can I fill dependencies to a concrete class that is not configured in StructureMap?If all constructor arguments (or marked setter properties) for a concrete type are non-primitive classes, and the dependency types are a Example Class
// "FilledConcreteClass" can have its dependencies set automatically assuming that both
// IStrategy and IWidget are configured under StructureMap with a default instance.
public class FilledConcreteClass
{
private readonly IWidget _widget;
private readonly IStrategy _strategy;
public FilledConcreteClass( IStrategy strategy, IWidget widget )
{
_strategy = strategy;
_widget = widget;
}
public IStrategy Strategy
{
get { return _strategy; }
}
public IWidget Widget
{
get { return _widget; }
}
}
// This class cannot be automatically filled with dependencies because the "name" argument to the
// constructor is a String or a primitive
public class CannotBeFilledConcreteClass
{
public CannotBeFilledConcreteClass( string name, Rule rule )
{
}
}
The class FilledConcreteClass can be created with the default instances of IWidget and IStrategy with the following code. FilledConcreteClass filled = (FilledConcreteClass)ObjectFactory.FillDependencies(typeof(FilledConcreteClass)); |