Richie

Sometimes at night when I look up at the stars, and see the whole sky just laid out there, don't you think I ain't remembering it all. I still got dreams like anybody else, and ever so often, I am thinking about how things might of been. And then, all of a sudden, I'm forty, fifty, sixty years old, you know?

IoC - StructureMap 2.6.1

StructureMap也是一个优秀的IoC框架,他的历史比较久,采用的Apache协议也非常开放,目前开发仍然非常活跃,项目主页上的文档也比较完善

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

posted on 2010-04-01 22:37  riccc  阅读(7391)  评论(1编辑  收藏  举报

导航