在Suteki.Shop中,未使用微软自已的Unity框架来实现IOC,而是使用了大名鼎鼎Castle Windsor。
因为引用了Windsor,就有必要简要介绍一下。而我的理解,这个IOC容器(Container)包括下面几个
重要概念:

容器(Container):Windsor是一个反转控制容器。它创建在一个微内核的基础之上,这个微内
核能够扫描类并且试图找到这些类用到哪些对象引用、对象依赖,然后把这些依赖信息提供给类使用。

组件(Component):也就是我们通常所说的业务逻辑单元及相应的功能实现,组件是一个可复
用的代码单元。它应该实现并暴露为一个服务。组件是实现一个服务或接口的类。

服务(Service) :也就是相应的组件接口或N个Component按业务逻辑组合而成的业务逻辑接口。
接口是服务的规范,它创建一个抽象层,你可以轻松的替换服务的实现。

扩张单元插件(Facilities):提供(可扩张)容器以管理组件。
      
     我们可以直接使用组件(会在下面的内容中提到),也可以把组件转换成相应的服务接口来使用。
 
     还记得上一篇文章中提到的Service吗? 说白了,它就是一个服务。而Suteki.Shop做的更“夸张”,
只要是带有业务逻辑性质的功能代码都可以被视为Component或服务,比如说前几篇文章中所提到的
Filter,ModelBinder。甚至是服务组件初始化的辅助类(WindsorServiceLocator)也一并拿下。

为了便于理解,下面就到Suteki.Shop中看一下其是如何做的:)
   
     首先我们看一下整个Suteki.Shop项目启动的入口,同时这也是Windsor IOC容器初始化的起点。
而这块功能代码是放在了Global.asax(Suteki.Shop\Global.asax)中的Application_Start方法中
实现的,下面是该方法的声明:

protected void Application_Start(object sender, EventArgs e)
{
    RouteManager.RegisterRoutes(RouteTable.Routes);
    InitializeWindsor();
}

代码中的RouteManager.RegisterRoutes是实现对Route规则的绑定,而规则的内容是被硬编码到
RouteManager中实现的。关于Route的资料网上有不少,园子里也有不少朋友写过,这里就不做说明了。

接就上面方法就会运行InitializeWindsor(),这就是Windsor容器初始化的方法:

/// <summary>
/// This web application uses the Castle Project's IoC container, Windsor see:
/// http://www.castleproject.org/container/index.html
/// </summary>
protected virtual void InitializeWindsor()
{
    if (container == null)
    {
        // create a new Windsor Container
        container = ContainerBuilder.Build("Configuration\\Windsor.config");

WcfConfiguration.ConfigureContainer(container);

ServiceLocator.SetLocatorProvider(() => container.Resolve<IServiceLocator>());
        // set the controller factory to the Windsor controller factory (in MVC Contrib)
        System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));
    }
}

注:“Configuration\\Windsor.config”中的内容较长,主要是一些XML配置节点。大家可以抽时
间阅读一下即可。

这个方法是今天讲解的主要内容,下面就介绍一下其中的代码。
   
     首先是判断container(IWindsorContainer类型)是否为空,如果容器为空则创建并初始化该容器。
也就是调用ContainerBuilder(Suteki.Shop\ContainerBuilder)类的Build方法来从外部的config文件
中加载默认信息。我们这里就看一下Build方法的实现:

public static IWindsorContainer Build(string configPath)
{
        var container = new WindsorContainer(new XmlInterpreter(configPath));

// register handler selectors
        container.Kernel.AddHandlerSelector(new UrlBasedComponentSelector(
            typeof(IBaseControllerService),
            typeof(IImageFileService),
            typeof(IConnectionStringProvider)
            ));

// automatically register controllers
        container.Register(AllTypes
            .Of<Controller>()
            .FromAssembly(Assembly.GetExecutingAssembly())
            .Configure(c => c.LifeStyle.Transient.Named(c.Implementation.Name.ToLower())));

container.Register(
            Component.For<IUnitOfWorkManager>().ImplementedBy<LinqToSqlUnitOfWorkManager>().LifeStyle.Transient,
            Component.For<IFormsAuthentication>().ImplementedBy<FormsAuthenticationWrapper>(),
            Component.For<IServiceLocator>().Instance(new WindsorServiceLocator(container)),
            Component.For<AuthenticateFilter>().LifeStyle.Transient,
            Component.For<UnitOfWorkFilter>().LifeStyle.Transient,
            Component.For<DataBinder>().LifeStyle.Transient,
            Component.For<LoadUsingFilter>().LifeStyle.Transient,
            Component.For<CurrentBasketBinder>().LifeStyle.Transient,
            Component.For<ProductBinder>().LifeStyle.Transient,
            Component.For<OrderBinder>().LifeStyle.Transient,
            Component.For<IOrderSearchService>().ImplementedBy<OrderSearchService>().LifeStyle.Transient,
            Component.For<IEmailBuilder>().ImplementedBy<EmailBuilder>().LifeStyle.Singleton
        );

return container;
}

首先是读入指定配置文件的XML结点信息,将构造一个 WindsorContainer实现,同时在其微内核中
添加“容器处理组件”的方式(AddHandlerSelector),注意这种处理方式是按我们在业务逻辑中规定
的方式处理的。

紧跟着又向该容器中注册了Controller,而且配置属性的LifeStyle被指定为Transient类型,这里
有必要介绍一下Castle容器的组件生存周期,主要有如下几种:

    Singleton : 容器中只有一个实例将被创建
    Transient : 每次请求创建一个新实例
    PerThread: 每线程中只存在一个实例
    PerWebRequest : 每次web请求创建一个新实例
    Pooled :使用"池化"方式管理组件,可使用PooledWithSize方法设置池的相关属性。

可以看到在本项目中,组件的生命周期基本上都被指定成为Transient类型,即当请求发生时创建,
在处理结束后销毁。

接着再看一下该方法的其余代码,也就是对ModelBinder,Filter,Service这类业务逻辑的组件注
册。同时我们看到有的组类在进行接口注册的同时还被绑定了默认的实现类,其这种硬编码的方法是
是一种“可选”方式。

说完了Build方法之前,再回到Global.asax文件中的InitializeWindsor方法,看一下其余的代码。
我们看到这样一行:

     WcfConfiguration.ConfigureContainer(container);

类WcfConfiguration的ConfigureContainer方法就是继续向当前创建的容器中添加组件,而这次要
加入的组件是Windows Live Writer的IMetaWeblog接口实现类,如下:

public static class WcfConfiguration
{
    public static void ConfigureContainer(IWindsorContainer container)
    {
        var returnFaults = new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true };

container.AddFacility<WcfFacility>(f =>
        {
            f.Services.AspNetCompatibility = AspNetCompatibilityRequirementsMode.Required;
            f.DefaultBinding = new XmlRpcHttpBinding();
        })
            .Register(
                Component.For<IServiceBehavior>().Instance(returnFaults),
                Component.For<XmlRpcEndpointBehavior>(),
                Component.For<IMetaWeblog>().ImplementedBy<MetaWeblogWcf>().Named("metaWebLog").LifeStyle.Transient
                );

}
}

如前面所说的,扩张单元插件(Facilities)可以在不更改原有组件的基础上注入你所需要的功能代码,
这里就使用了其AddFacility方法来添加扩展单元来注册并管理我们的Windows Live Writer组件。

下面继分析InitializeWindsor方法中的其余代码,看完了ConfigureContainer方法,接着就是下面这
一行代码了:

     ServiceLocator.SetLocatorProvider(() => container.Resolve<IServiceLocator>());

刚看到这一行让我感觉似曾相识,记得以前在看Oxite的Global.asax中也看过类似的这样一行代码。

     ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));  

只不过那个项目中用的是 Unity而不是Castle Windsor。但实际的功能是一样的。即完成对容器中服务
地址的解析绑定。有了它,就可以通过Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase
中所定义的方法如:DoGetInstance或DoGetAllInstances 来获取相应的服务组件(集合)的实例。

比如本项目中的DoGetInstance及DoGetAllInstances()实现代码如下:

(文件位于:Suteki.Common\Windsor\WindsorServiceLocator.cs):

protected override object DoGetInstance(Type serviceType, string key)
{
    if (key != null)
        return container.Resolve(key, serviceType);
    return container.Resolve(serviceType);
}

/// <summary>
/// When implemented by inheriting classes, this method will do the actual work of
/// resolving all the requested service instances.
/// </summary>
/// <param name="serviceType">Type of service requested.</param>
/// <returns>
/// Sequence of service instance objects.
/// </returns>
protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
{
    return (object[])container.ResolveAll(serviceType);
}

注,对该WindsorServiceLocator类的IOC绑定在ContainerBuilder.Build中,如下:

 
  container.Register(
       Component.For<IUnitOfWorkManager>().ImplementedBy<LinqToSqlUnitOfWorkManager>().LifeStyle.Transient,
       Component.For<IFormsAuthentication>().ImplementedBy<FormsAuthenticationWrapper>(),
       Component.For<IServiceLocator>().Instance(new WindsorServiceLocator(container)),
 

而InitializeWindsor方法中的最后一行代码如下:

     System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));

这里要说明的是WindsorControllerFactory这个类是在 MvcContrib项目中提供的,用于构造一个
Castle项目类型的Controller工厂。
     
    
      好了,今天的内容可能有点杂,主要就是Castle闹的,因为其中有一些概念要了解之后才能把项目中
的代码看懂。不过从整体上来看,Suteki.Shop的IOC机制实现的还是很清晰的,没什么太难看的代码。

今天就先到这里了。
    
     
   
      原文链接: http://www.cnblogs.com/daizhj/archive/2009/05/26/1456678.html

作者: daizhj,代震军,LaoD

Tags: mvc,Suteki.Shop,Castle,IOC

网址: http://daizhj.cnblogs.com/

Asp.net MVC 示例项目Suteki.Shop分析之---IOC(控制反转)相关推荐

  1. Asp.net MVC 示例项目Suteki.Shop分析之---结束篇

    到今天,这个系列的文章就要先告一段落了.其中我用了10篇文章也没有穷尽该项目的设计思想,只能从中捡了一些我感兴趣的东西进行了分析和说明,正所谓兴趣是最大的动力.当然限于本人水平有限,难免有一些认识上的 ...

  2. Asp.net MVC 示例项目Suteki.Shop分析之---ViewData

            使用强类型的ViewData好处有许多,比如说在IDE中就会有更好的支持,比如代码提示.同时在View与Controller之间有更严谨的"约定".在Suteki. ...

  3. Asp.net MVC 示例项目Suteki.Shop分析之---Model和Service

    老戴的文章,自己去看吧 http://www.cnblogs.com/daizhj/archive/2009/05/31/1455867.html 转载于:https://www.cnblogs.co ...

  4. 图文详解远程部署ASP.NET MVC 5项目

    图文详解远程部署ASP.NET MVC 5项目 原文:图文详解远程部署ASP.NET MVC 5项目 话外篇: 由于感觉自己的机器比较慢,配置不好,所以最近想把之前的项目部署到实验室的服务器上,但是由 ...

  5. 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus

    最新的Mono 4.4已经支持运行asp.net mvc5项目,有的同学听了这句话就兴高采烈的拿起Visual Studio 2015创建了一个mvc 5的项目,然后部署到Mono上,浏览下发现一堆错 ...

  6. angular2+typescript在asp.net MVC Web项目上的实现

    网上现在还没有关于angular2+typescript在asp.net mvc web项目上的实现的系统介绍,这里我也只是探索到了一个简单的方式,还有很多问题没能解决.但是能有个好的开头也值得记录一 ...

  7. 【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入代码示例 )

    文章目录 总结 一.Android 事件依赖注入示例 1.创建依赖注入库 2.声明注解 (1).修饰注解的注解 (2).修饰方法的注解 3.Activity 基类 4.动态代理类调用处理程序 5.依赖 ...

  8. 【IOC 控制反转】Android 视图依赖注入 ( 视图依赖注入步骤 | 视图依赖注入代码示例 )

    文章目录 总结 一.Android 视图依赖注入步骤 二.Android 布局依赖注入示例 1.创建依赖注入库 2.声明注解 3.Activity 基类 4.依赖注入工具类 5.客户端 Activit ...

  9. 利用Powershell自动部署asp.net mvc网站项目 (一)

    这一篇中我们会写一些关于自动化部署的代码.我们会使用 Powershell 书写这类代码. 你将发现这篇文章中涉及的东西非常具体,有的要求甚至相当苛刻且可能不具有通用性.这是因为部署从来都是跟环境打交 ...

  10. ASP.NET MVC 开源项目 收集

    Oxite NerdDinner MvcStore Suteki.Shop(http://code.google.com/p/sutekishop/downloads/list)(DEMO:http: ...

最新文章

  1. Python代码运行助手
  2. 如何解读「量子计算应对大数据挑战:中国科大首次实现量子机器学习算法」?——是KNN算法吗?...
  3. APACHE如何里一个站点绑定多个域名?用ServerAlias
  4. Codeforces 1093D Beautiful Graph
  5. java编程实现素数环_结对编程(JAVA实现)
  6. Win11如何切换应用商店网络 Win11切换应用商店网络的方法
  7. 2015年《大数据》高被引论文 Top10
  8. es6 Object.getOwnPropertyDescriptors()
  9. java对象与内存控制
  10. bootstrap3-iframe-modal子页面在父页面显示模态框
  11. 六月计划#2A(6.10-6.16)
  12. drools部署教程
  13. JAVA基础知识点大全之一
  14. 中介效应、调节效应与交互作用咋回事?
  15. centos修改镜像源
  16. 把数字翻译成字符串(递归,动态规划)
  17. 如何提升自己的宣传效果?从这两个点开始
  18. 奔腾的芯——英特尔公司
  19. 学习Android启动初始化 App StartUp
  20. thymleaf 使用三目运算多个条件判断的写法

热门文章

  1. pythonATM,购物车项目实战_补充1-结构图
  2. crontab关于 >/dev/null 2>1输出重定向问题
  3. python检验文件命名_Python如何检查文件名是否为UTF8?
  4. python爬人人贷代码视频_利用python爬取人人贷网的数据
  5. CS224N笔记——依存句法分析
  6. Tomcat(介绍,JDK安装,Tomcat安装,配置Tomcat监听80端口)
  7. bash的算术运算和条件测试语句
  8. HAXM 6.0.5显示不兼容Windows
  9. Python:线程、进程与协程(5)——multiprocessing模块(2)
  10. 【分析】浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang)...