IoC - StructureMap 2.6.1
StructureMap也是一个优秀的IoC框架,他的历史比较久,采用的Apache协议也非常开放,目前开发仍然非常活跃,项目主页上的文档也比较完善
基本示例
下载StructureMap,基本实例中只需要引用StructureMap.dll文件,并引用命名空间StructureMap
下面是我们需要使用IoC的示例代码,我们要创建ContactController,希望通过IoC为ContactController的构造函数提供IContactValidator和IContactRepository的实例对象
上面使用的StructureMap的Registry DSL的fluent interface注册依赖的组件(Castle Windsor也支持类似的方式),这些配置也可以使用xml。下面的配置中,PlugginType、PluggedType类似于Windsor中的service、type配置属性,即制定服务的接口和具体实现类;DefaultInstance节点指定接口的默认实现类,类似Windsor中采用第一个配置的节点作为默认实现类,StructureMap是使用DefaultInstance节点;为一个接口配置多个实现类时,使用Instance配置节点,同Windsor,配置节点上通过添加一个key值进行标识,使用ObjectFactory获取实例对象时通过指定这个key值可以获取到不同实现类的实例对象。详细的xml配置说明参考项目的官方文档说明
上面的示例使用构造器注入,StructureMap同样支持setter注入等方式
其他特性
自动扫描
StructureMap支持自动扫描,接口形如public void Scan(Action<IAssemblyScanner> action)
通过scan方法的Action参数可以指定需要扫描的assembly,默认情况下StructureMap扫描整个assembly的类型,查找那些使用了PluginFamily或者Pluggable attribute的类型,在action表达式中还可以指定include、exclude某些类型,能够被自动扫描到的类型必须有public的构造器,构造器不能有基本类型的参数(可以有其他类型的参数,StructureMap能够自动构造出这些参数的实例对象,例如有默认public的构造器,或者是其他标记为接受StructureMap容器管理的类型等)
生命周期
StructureMap容器托管的对象,生命周期支持以下几种(xml中的Scope配置,或者是初始化时的相关方法例如CacheBy进行设置)
PerRequest: 每次请求都新建一个实例对象
Singleton: 单例
ThreadLocal: 每线程对应一个实例
HttpContext: 在一个HttpContext上唯一
HttpSession: 在一个HttpSession上唯一
Hybrid: 混合模式,如果存在HttpContext则设置在HttpContext上,否则设置在当前线程上
另外StructureMap也支持使用自定义的生命周期,实现StructureMap.Pipeline.ILifecycle接口即可
拦截处理
StructureMap的拦截处理不是为了实现AOP之类的功能,而是服务于特定类型的IoC
比如可以为某个类型提供一些方法调用,创建该类型的实例对象之后立即调用这些方法;比如有时创建出对象实例之后,可能像实现类似Decorator模式,使用另为的Decorator类包装该实例对象并返回给请求者;或者自定义一些拦截器,让StructureMap创建出某些对象后调用这些拦截器进行处理,再将其返回给请求者
AutoMock
StructureMap的一个亮点便是支持自动构造Mock对象用于测试,StructureMap支持RhinoMocks和Moq,简单演示如下
仍然以前面的ContactController、ContactRepository、ContactValidator等类进行演示,创建Auto Mock对象的测试代码如下(需要引用命名空间StructureMap.AutoMocking):
1. 搜索ContactController构造器的依赖关系,发现IContactRepository、IContactValidator依赖对象
2. 使用RhinoMocks的MockRepository.CreateMock<T>()方法创建IContactRepository、IContactValidator实例对象
3. 调用ContactController的构造器,创建ContactController对象
在ContactController.Save方法中,我们将IContactRepository、IContactValidator的类型信息输出来,结果示例如下:
基本示例
下载StructureMap,基本实例中只需要引用StructureMap.dll文件,并引用命名空间StructureMap
下面是我们需要使用IoC的示例代码,我们要创建ContactController,希望通过IoC为ContactController的构造函数提供IContactValidator和IContactRepository的实例对象
public class ContactEntity
{
public string Name { get; set; }
public DateTime Birthday { get; set; }
public string IDCard { get; set; }
}
public interface IContactValidator
{
bool Validate(ContactEntity contact);
}
public class ContactValidator : IContactValidator
{
public bool Validate(ContactEntity contact)
{
Console.WriteLine(string.Format("Contact \"{0}\" has been validated.", contact.Name));
return true;
}
}
public interface IContactRepository
{
bool Save(ContactEntity contact);
}
public class ContactRepository : IContactRepository
{
private string _connectionString;
public ContactRepository(string connectionString)
{
this._connectionString = connectionString;
}
public bool Save(ContactEntity contact)
{
Console.WriteLine(string.Format("Contact \"{0}\" has been saved to:", contact.Name));
Console.WriteLine(this._connectionString);
return true;
}
}
public class ContactController
{
private IContactValidator _validator;
private IContactRepository _repository;
public ContactController(IContactValidator validator, IContactRepository repository)
{
this._repository = repository;
this._validator = validator;
}
public void Save(ContactEntity contact)
{
this._validator.Validate(contact);
this._repository.Save(contact);
}
}
下面就是使用StructureMap的测试代码了:
static void Main(string[] args)
{
ObjectFactory.Initialize(x =>
{
x.For<IContactValidator>().Use<ContactValidator>();
x.For<IContactRepository>()
.Use<ContactRepository>()
.Ctor<ContactRepository>("connectionString")
//从app.config的Connection-String中读取数据库连接字符串
//作为构造函数的connectionString参数值
.EqualToAppSetting("Connection-String");
});
ContactEntity contact = new ContactEntity()
{
Name = "Richie",
Birthday = new DateTime(1970, 1, 1),
IDCard = "490192197001016191"
};
//与Castle Windsor不一样的地方:ContactController不需要注册到StructureMap中
//也可以使用StructureMap来创建实例对象,StructureMap根据请求的实例对象的构造函数
//依赖关系以及初始化时注册的组件,自动处理
ContactController controller = ObjectFactory.GetInstance<ContactController>();
controller.Save(contact);
Console.ReadKey();
}
上面使用的StructureMap的Registry DSL的fluent interface注册依赖的组件(Castle Windsor也支持类似的方式),这些配置也可以使用xml。下面的配置中,PlugginType、PluggedType类似于Windsor中的service、type配置属性,即制定服务的接口和具体实现类;DefaultInstance节点指定接口的默认实现类,类似Windsor中采用第一个配置的节点作为默认实现类,StructureMap是使用DefaultInstance节点;为一个接口配置多个实现类时,使用Instance配置节点,同Windsor,配置节点上通过添加一个key值进行标识,使用ObjectFactory获取实例对象时通过指定这个key值可以获取到不同实现类的实例对象。详细的xml配置说明参考项目的官方文档说明
<configuration>
<configSections>
<section
name="StructureMap"
type="StructureMap.Configuration.StructureMapConfigurationSection,StructureMap"/>
</configSections>
<StructureMap MementoStyle="Attribute">
<DefaultInstance
PluginType="StructureMap.Test.IContactValidator,StructureMap.Test"
PluggedType="StructureMap.Test.ContactValidator,StructureMap.Test"
Scope="Singleton" />
<DefaultInstance
PluginType="StructureMap.Test.IContactRepository,StructureMap.Test"
PluggedType="StructureMap.Test.ContactRepository,StructureMap.Test"
Scope="Singleton"
connectionString="server=localhost; User ID=root; Psw=dev; datasource=test;" />
</StructureMap>
</configuration>
初始化的代码改成下面这样就可以了(指定从app.config读取配置,也可以使用默认的StructureMap.config文件,或自定义的config文件都可以):
ObjectFactory.Initialize(x =>
{
x.PullConfigurationFromAppConfig = true;
});
上面的示例使用构造器注入,StructureMap同样支持setter注入等方式
其他特性
自动扫描
StructureMap支持自动扫描,接口形如public void Scan(Action<IAssemblyScanner> action)
通过scan方法的Action参数可以指定需要扫描的assembly,默认情况下StructureMap扫描整个assembly的类型,查找那些使用了PluginFamily或者Pluggable attribute的类型,在action表达式中还可以指定include、exclude某些类型,能够被自动扫描到的类型必须有public的构造器,构造器不能有基本类型的参数(可以有其他类型的参数,StructureMap能够自动构造出这些参数的实例对象,例如有默认public的构造器,或者是其他标记为接受StructureMap容器管理的类型等)
生命周期
StructureMap容器托管的对象,生命周期支持以下几种(xml中的Scope配置,或者是初始化时的相关方法例如CacheBy进行设置)
PerRequest: 每次请求都新建一个实例对象
Singleton: 单例
ThreadLocal: 每线程对应一个实例
HttpContext: 在一个HttpContext上唯一
HttpSession: 在一个HttpSession上唯一
Hybrid: 混合模式,如果存在HttpContext则设置在HttpContext上,否则设置在当前线程上
另外StructureMap也支持使用自定义的生命周期,实现StructureMap.Pipeline.ILifecycle接口即可
拦截处理
StructureMap的拦截处理不是为了实现AOP之类的功能,而是服务于特定类型的IoC
比如可以为某个类型提供一些方法调用,创建该类型的实例对象之后立即调用这些方法;比如有时创建出对象实例之后,可能像实现类似Decorator模式,使用另为的Decorator类包装该实例对象并返回给请求者;或者自定义一些拦截器,让StructureMap创建出某些对象后调用这些拦截器进行处理,再将其返回给请求者
AutoMock
StructureMap的一个亮点便是支持自动构造Mock对象用于测试,StructureMap支持RhinoMocks和Moq,简单演示如下
仍然以前面的ContactController、ContactRepository、ContactValidator等类进行演示,创建Auto Mock对象的测试代码如下(需要引用命名空间StructureMap.AutoMocking):
ObjectFactory.Initialize(x =>
{
x.PullConfigurationFromAppConfig = true;
});
ContactEntity contact = new ContactEntity()
{
Name = "Richie",
Birthday = new DateTime(1970, 1, 1),
IDCard = "490192197001016191"
};
var autoMock = new RhinoAutoMocker<ContactController>(MockMode.AAA);
ContactController controller = autoMock.ClassUnderTest;
controller.Save(contact);
Console.ReadKey();
其处理步骤为:1. 搜索ContactController构造器的依赖关系,发现IContactRepository、IContactValidator依赖对象
2. 使用RhinoMocks的MockRepository.CreateMock<T>()方法创建IContactRepository、IContactValidator实例对象
3. 调用ContactController的构造器,创建ContactController对象
在ContactController.Save方法中,我们将IContactRepository、IContactValidator的类型信息输出来,结果示例如下:
浙公网安备 33010602011771号