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的类型信息输出来,结果示例如下: