关于NHibernate的应用暂告一段落,在Asp.Net大型项目实践(2)-新建项目及分层(附源码)中,我们为系统分了几个逻辑层,对于层与层之间的调用我们要实现一下几点:

1.层与层之间只通过接口调用

2.接口所对应的具体实现通过XML配置指定

3.可能会对接口实例的生存周期进行管理

这里我们使用Unity的依赖注入容器(Dependency Injection, DI)去实现,你问我为啥不用所谓工厂模式?懒得说了自己去google吧...

为什么使用Unity实现层间调用请看Asp.Net大型项目实践-关键技术方案选择理由及思路

先回顾一下我们项目的分层(这个图画反了,凑合看吧...):

unity 调用类 unity调用接口_游戏

数据访问层Repositories:主要用NHibernate访问数据库,但也有可能去访问其他模块或系统的WebService,也有可能用Linq去访问一些缓存(内存中的)数据,也有可能访问XML,文本文件等等....
业务领域层Core:系统的核心层,所有与数据访问无关的业务逻辑都应该内聚在这里,业务领域对象理论上应该是充血的,内聚自己的业务逻辑。但有一些业务逻辑在设计的时候涉及到了多个业务领域对象 ,我们很难决定放在哪个具体的业务对象里,所以我们有一个Service层来放这种业务逻辑。
外观层(设计模式之外观模式)Facade:把数据访问接口,业务领域对象的业务逻辑,Service接口简单的封装一下成为Facade层接口供展示层UI或SOA层调用,这个层需要注意的是它只是简单的封装,免得UI层调太多层的接口,这层不应含有业务逻辑。
SOA层:因为系统比较庞大 模块很多,且业务上要求各大模块间需要一定解耦,所以这一层作用是作为各大粗粒度模块间调用以及给其他系统调用,比如有基础数据管理大模块和门诊挂号大模块,他们之间的调用是必须要通过SOA层的,而不能直接走Facade层,传输的对象应该新建DTO数据传输对象,而不应该直接传递业务领域对象,从而通过SOA层我们把各个粗粒度模块完全隔离开。这个层取名为SOA也许不大恰当,大家也不必深究...计划是采用WCF 这样可以灵活的配置通讯方式
表现层Presentation:由Asp.net MVC的Action给ExtJs传输数据 ,Controler只需调用Facade接口
公共类库FrameWork:整个项目框架的公用代码,相当于公共类库,也许叫FrameWork不大恰当 呵呵

 

接下来我们还是以之前的字典维护功能为例

字典项的持久层Repositorie

接口:




public 
     
   interface 
    IDictionaryRepository : IRepository 
   < 
   Dictionary 
   >
 
  
{
 
  
}



接口的实现:




public 
     
   class 
    DictionaryRepositoryImpl : RepositoryNhbImpl 
   < 
   Dictionary 
   > 
   , IDictionaryRepository
 
  
{
 
  
  //实现见源码,略
 
  
}



持久层除了会引用业务对象之外不会调用别的层

字典项的外观层Facade

这层可能需要调用Repositorie层,Service层,以及业务领域对象的方法 进行简单封装后提供给UI层调用,这个例子里只需调用Repositorie层

假设我们这样实例化Facade:




IDictionaryRepository repository  
   = 
     
   new 
    DictionaryRepositoryImpl();
IDictionaryFacade facade  
   = 
     
   new 
    DictionaryFacadeImpl(repository);



接口:




unity 调用类 unity调用接口_游戏_02

unity 调用类 unity调用接口_MVC_03

代码


public 
      
    interface 
     IDictionaryFacade : IDomainFacade
 {
     // 
    保存字典 
    
       
    void 
     SaveOrUpdate(Dictionary entity);
     // 
    获取字典 
    
      Dictionary GetDictionary( 
    string 
     id);

 Dictionary LoadDictionary(     string 
     id);
     // 
    删除字典 
    
       
    void 
     DeleteDictionary( 
    string 
     id);
     // 
    获取字典列表By字典类别Id 
    
      IList 
    < 
    Dictionary 
    > 
     GetPlistByCategoryId( 
    string 
     id,  
    int 
     start,  
    int 
     limit,  
    string 
     sort,  
    string 
     dir, List 
    < 
    DataFilter 
    > 
     filters,  
    out 
      
    long 
     total);
 }


 实现(注意构造函数):


unity 调用类 unity调用接口_游戏_02

unity 调用类 unity调用接口_MVC_03

代码

public       
    class 
     DictionaryFacadeImpl : IDictionaryFacade
 {
     //     注意这里 
    
           private 
      
    readonly 
     IDictionaryRepository DictionaryRepository;
     public      DictionaryFacadeImpl(IDictionaryRepository DictionaryRepository)
 {
     this     .DictionaryRepository  
    = 
     DictionaryRepository;
 }

     #region      IDictionaryFacade 成员 
    

     public       
    void 
     SaveOrUpdate(Demo.HIS.Infrastructure.Core.Dictionary entity)
 {
 DictionaryRepository.SaveOrUpdate(entity);
 }

     public      Demo.HIS.Infrastructure.Core.Dictionary GetDictionary( 
    string 
     id)
 {
     return      DictionaryRepository.Get(id);
 }

     public      Demo.HIS.Infrastructure.Core.Dictionary LoadDictionary( 
    string 
     id)
 {
     return      DictionaryRepository.Load(id);
 }

     public       
    void 
     DeleteDictionary( 
    string 
     id)
 {
 DictionaryRepository.Delete(id);
 }

     public      IList 
    < 
    Demo.HIS.Infrastructure.Core.Dictionary 
    > 
     GetPlistByCategoryId( 
    string 
     id,  
    int 
     start,  
    int 
     limit,  
    string 
     sort,  
    string 
     dir, List 
    < 
    Demo.HIS.FrameWork.DomainBase.DataFilter 
    > 
     filters,  
    out 
      
    long 
     total)
 {
return DictionaryRepository.GetPlistByCategoryId(id, start, limit, sort, dir, filters,      out      total);
 }

     #endregion     
 }


字典项的表现层Presentation(Demo.HIS.MVC)

注1:这里我默认你已经具备Asp.net MVC的基本知识

注2:默认的Asp.net的Controller是放在网站项目下的,因为项目模块比较多,为管理方便我们把Controller放在Demo.HIS.MVC这个类库里

首先我们为所有的Controller准备一个基类BaseController它继承了Asp.net Mvc的Controller类(现在是空的以后有用):


//     所有Controller都要继承的基类    
         public 
     
   class 
    BaseController:Controller
 {

 }

字典管理功能的Controller(注意构造函数):


unity 调用类 unity调用接口_游戏_02

unity 调用类 unity调用接口_MVC_03

代码

namespace      Dawn.HIS.MVC.Controllers
{
     //     字典管理功能的Controller     
           public       
    class 
     InfraDictionaryController : BaseController
 {
     private           readonly 
     IDictionaryFacade DictionaryFacade;
     public      InfraDictionaryController(IDictionaryFacade DictionaryFacade)
 {
     this     .DictionaryFacade      = 
     DictionaryFacade;
 }

     //     这只是个例子说明如何调用Facade     
           public      ActionResult SaveOrUpdateDictionary()
 {
 var entity      =           new 
     Dictionary();
 DictionaryFacade.SaveOrUpdate(entity);
     return      Content(     "" 
    );
 }
 }
}


这样我们的层就“到底”了,唯一的问题是Controller虽然也有了构造函数,但是谁去创建Controller呢,这个问题暂时放一下,我们来在项目中实现Unity容器的初始化和调用。

我们新建一个类ContainerFactory去创建Unity容器:

注1:这里我默认你已经具备Unity以及依赖注入的基本知识

注2:我们没有像官方例子一样把配置放在webconfig里,因为我们的模块实在太多,我把配置放在独立的xml文件里,所以这里做了些处理

注3:由于我们的模块实在太多太多-_-b,把所有的配置放在一个xml文件里也会难以管理,所以我们按业务粗粒度大模块划分,把各个大模块的配置分别放在不同的xml文件里,这里只有一个

 


unity 调用类 unity调用接口_游戏_02

unity 调用类 unity调用接口_MVC_03

代码

namespace      Demo.HIS.MVC.CommonSupport
{
     public           static       
    class 
     ContainerFactory
 {
     public           static      IUnityContainer GetContainer()
 {
 IUnityContainer Container      =           new      UnityContainer();

 ExeConfigurationFileMap infraFileMap      =           new      ExeConfigurationFileMap();
 infraFileMap.ExeConfigFilename      =      HttpContext.Current.Server.MapPath(     "     ~/unity.di.infrastructure.config 
    " 
    );
 UnityConfigurationSection infraConfig      =      (UnityConfigurationSection)ConfigurationManager
 .OpenMappedExeConfiguration(infraFileMap, ConfigurationUserLevel.None)
 .GetSection(     "     unity     "     );
     if      (infraConfig.Containers.Default      !=       
    null 
    )
 {
 infraConfig.Containers.Default.Configure(Container);
 }

     return      Container;
 }
 }
}


 Unity的XML配置文件(具体含义自己去google..):


unity 调用类 unity调用接口_游戏_02

unity 调用类 unity调用接口_MVC_03

代码

<?     xml version     =     "     1.0     " 
     encoding 
    = 
    " 
    utf-8 
    " 
      
    ?> 
    
     <     configuration     >     
     <     configSections     >     
     <     section name     =     "     unity 
    " 
    
 type     =     "     Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35     "     /> 
    
     </     configSections     >     

     <     unity     >     
     <     typeAliases     >     
     <!--     BeginRepository     -->     
     <     typeAlias alias     =     "     IDictionaryRepository 
    " 
     type 
    = 
    " 
    Demo.HIS.Infrastructure.Core.Repositories.IDictionaryRepository, Infrastructure.Core 
    " 
      
    /> 
    
     <!--     EndRepository     -->     

     <!--     BeginService     -->     

     <!--     EndService     -->     

     <!--     BeginFacade     -->     
     <     typeAlias alias     =     "     IDictionaryFacade 
    " 
     type 
    = 
    " 
    Demo.HIS.Infrastructure.Facade.IDictionaryFacade, Infrastructure.Facade 
    " 
      
    /> 
    
     <!--     EndFacade     -->     
     </     typeAliases     >     
     <     containers     >     
     <     container     >     
     <     types     >     
     <!--     BeginRepository     -->     
     <     type type     =     "     IDictionaryRepository 
    " 
     mapTo 
    = 
    " 
    Demo.HIS.Infrastructure.Repositories.DictionaryRepositoryImpl, Infrastructure.Repositories 
    " 
      
    /> 
    
     <!--     EndRepository     -->     

     <!--     BeginService     -->     

     <!--     EndService     -->     

     <!--     BeginFacade     -->     
     <     type type     =     "     IDictionaryFacade 
    " 
     mapTo 
    = 
    " 
    Demo.HIS.Infrastructure.Facade.DictionaryFacadeImpl, Infrastructure.Facade 
    " 
      
    /> 
    
     <!--     EndFacade     -->     
     </     types     >     
     </     container     >     
     </     containers     >     
     </     unity     >     
     </     configuration     >


我们自定义一个UnityControllerFactory(继承自Asp.Net MVC的DefaultControllerFactory)去创建我们的 Controller:


unity 调用类 unity调用接口_游戏_02

unity 调用类 unity调用接口_MVC_03

代码

namespace      Dawn.HIS.MVC.CommonSupport
{
     public           class      UnityControllerFactory : DefaultControllerFactory
 {
     private           readonly      IUnityContainer container;

     public      UnityControllerFactory(IUnityContainer container)
 {
     //     要做异常处理     
           this     .container      =      container;
 }
     protected           override      IController GetControllerInstance(Type controllerType)
 {    
//这里把Controller实例注册到了unity容器
 IController icontroller      =      container.Resolve(controllerType)      as      IController;
     return      icontroller;
 }
 }
}


在DemoHISApplication(HttpApplication)里初始化Uinty:

1.用Application全局应用程序变量缓存Unity容器

2.告诉Asp.netMVC用我们自定义的UnityControllerFactory去创建Controller实例


unity 调用类 unity调用接口_游戏_02

unity 调用类 unity调用接口_MVC_03

代码

private           void      initContainer()
 {
     if      (Application[     "     container     "     ]      == 
      
    null 
    )
 {
 Application.Add(     "     container     "     , ContainerFactory.GetContainer());
 }
 ControllerBuilder.Current.SetControllerFactory(     new      UnityControllerFactory((IUnityContainer)Application[     "     container     "     ]));
 }


这样我们就用unity实现了层间调用

你可以试一试访问源码里的/InfraDictionary/SaveOrUpdateDictionary,调试发现已经成功:)

源码:HISDemo-7.rar