ASP.NET Mvc + NHibernate + Unity Application Block 示例程序

       今天无意间看到了Unity Application Block (以下简称Unity),感觉很不错,用起来挺方便的说。于是一时兴起写了这个留言本的小示例。数据库操作采用的NHibernate,UI直接用的

ASP.NET Mvc了。项目基于VS2010 + SQLServer 2005 ,就一个表的增删改查操作很简单。目的是为了体验下Unity的Ioc功能。

 

国际惯例,先上个项目结构图

项目只是演示使用,未建立公共类和配置项抽象出来等工作,各个项目如下:

Guestbook.Biz 业务层,具体业务实现。这里只实现了增删改查

Guestbook.Dal 持久层,基于NHibernate的ORM映射。实现增删改查

Guestbook.IBiz 业务层接口,给UI引用实现解藕。UI层不直接引用具体业务类,实现面向接口

Guestbook.IDal 持久层接口,给Biz引用实现解藕。方便更换不同数据库持久类(PS;虽然NHibernate 已经可以支持多库,这里纯为了娱乐)

Guestbook.Model 持久实体,NHibernate的映射文件也放到这个类库里面了

Guestbook.Unity 简单封装了一下Unity,传入相应接口即可New相应的在Web.Config中配置的具体业务类

Guestbook.Web UI层,ASP.NET Mvc项目。控制器直接引用的业务接口IBiz和Model还有Unity其它全部不引用

 

采取从下往上依次说各层的东西。首先从数据库。。。。(略)---从持久层说起吧。持久层采用了NHibernate基本配置和映射配置就不说了(hkgoogle),首先在Guestbook.Dal中写了一个NHibernateHelper帮助类,代码如下:

 

代码
    /// <summary>
    
/// NHibernate操作辅助类
    
/// </summary>
    public class NHibernateHelper
    {
        
private ISessionFactory _sessionFactory;
        
public NHibernateHelper()
        {
            _sessionFactory 
= GetSessionFactory();
        }
        
private ISessionFactory GetSessionFactory()
        {
            Configuration cfg 
= new Configuration();
            ISessionFactory sf 
=
                cfg.Configure().BuildSessionFactory();
            
return sf;
        }
        
public ISession GetSession()
        {
            ISession session 
= _sessionFactory.OpenSession();
            
return session;
        }
    }

 

以上就是创建个NHibernate的Session。

接下来是在Guestbook.IDal定义持久层相关的接口,首先是一个通用的增删改查接口,如下:

 

代码
    /// <summary>
    
/// 数据执行类接口
    
/// </summary>
    
/// <typeparam name="T"></typeparam>
    public interface IDbObject<T>
    {
        
void Save(T entity);
        
void Delete(T entity);
        
void Update(T entity);
        T Load(
int sysNo);
        IList
<T> GetList();
    }

 

定义基本的增删改查,是个泛型接口,这样实现它的类可以接收所有实本类,实现通用的方法。

接下来在Guestbook.Dal 定义一个 DbObject<T>基类,实现IDbObject<T>的增删改查方法,并做具体的实现,像下面这样:

 

 

代码
/// <summary>
    
/// 数据执行基础泛型类
    
/// </summary>
    
/// <typeparam name="T"></typeparam>
    public class DbObject<T>:IDbObject<T> where T:class
    {
        
private ISession _session;
        
public DbObject()
        {
            NHibernateHelper nhbHelper 
= new NHibernateHelper();
            _session 
= nhbHelper.GetSession();
        }
        
#region IDbObject<T> 成员

        
public void Save(T entity)
        {
            _session.Save(entity);
            _session.Flush();
        }

        
public void Delete(T entity)
        {
            _session.Delete(entity);
            _session.Flush();
        }

        
public void Update(T entity)
        {
            _session.Update(entity);
            _session.Flush();
        }

        
public T Load(int sysNo)
        {
            
return _session.Load<T>(sysNo);
        }

        
public IList<T> GetList()
        {
            
return _session.CreateCriteria<T>().AddOrder(NHibernate.Criterion.Order.Asc("SysNo")).List<T>();
        }

        
#endregion

 

比如 Save(T entity) 方法,实现具体的_session.Save(entity);_session.Flush();方法。通过NHibernate操作数据库。接下来就可以具体的持久业务类继承这个操作基类了。下面以Guestbook 为原型做相关讲解。为了数据层解藕,先建接口IGuestbookDal如下:

 

代码
/// <summary>
    
/// 留言本数据操作接口
    
/// </summary>
    public interface IGuestbookDal
    {
        
void Save(GuestbookInfo entity);
        
void Delete(GuestbookInfo entity);
        
void Update(GuestbookInfo entity);
        GuestbookInfo Load(
int sysNo);
        IList
<GuestbookInfo> GetList();
    }

 

 

然后在Guestbook.Dal中建一个具体持久类,这个类继承DbObject<GuestbookInfo>基类并实现IGuestbookDal接口,代码如下:

 

    /// <summary>
    
/// 留言本数据处理类
    
/// </summary>
    public class GuestbookDal:DbObject<GuestbookInfo>,IGuestbookDal
    {

    }

 

 具体操作已经在泛型基类DbObject中实现了,所以这个类不用再实现什么操作即可。再加比如UserDal;ProductDal都可以直接继承不用实现就可以了。大大减少了很多工作量(之前园子里有觉得应该取消泛型,这么好的东西给我留着吧。阿们)。这样持久层基本就完成了。接下来说说业务类。

 

首先,一切为了解藕,一切为了面向接口。主阿,饶恕我吧。先在Guestbook.IBiz中定义个业务接口IGuestbookBiz吧:

 

代码
  /// <summary>
    
/// 留言本业务接口
    
/// </summary>
    public interface IGuestbookBiz
    {
        
void Save(GuestbookInfo entity);
        
void Delete(GuestbookInfo entity);
        
void Update(GuestbookInfo entity);
        GuestbookInfo Load(
int sysNo);
        IList
<GuestbookInfo> GetList();
    }

 

这没啥说的了,再说大家都烦了。再紧跟着在Guestbook.Biz中建一个业务类GuestbookBiz 实现 以上接口:

 

 

代码
/// <summary>
    
/// 留言本业务类
    
/// </summary>
    public class GuestbookBiz:IGuestbookBiz
    {
        
private IGuestbookDal _guestbookDal = UnityHelper.UnityToT<IGuestbookDal>("DalType");

        
#region IGuestbookBiz 成员
        
public void Save(GuestbookInfo entity)
        {
            _guestbookDal.Save(entity);
        }

        
public void Delete(GuestbookInfo entity)
        {
            _guestbookDal.Delete(entity);
        }

        
public void Update(GuestbookInfo entity)
        {
            _guestbookDal.Update(entity);
        }

        
public GuestbookInfo Load(int sysNo)
        {
            
return _guestbookDal.Load(sysNo);
        }

        
public IList<GuestbookInfo> GetList()
        {
            
return _guestbookDal.GetList();
        }

        
#endregion
    }

 

注意这句 private IGuestbookDal _guestbookDal = UnityHelper.UnityToT<IGuestbookDal>("DalType");,这里是业务层引用持久层,并不是直接New的,而是通过持久接口IGuestbookDal定义的,通过Unity加载进来的。这样就实现了相当成份的解藕了,不是由使用者去引用并实例被引用者,这个操作是由Ioc容器来做(这里是Unity)。这里用到了UnityHelper类了,它的写法如下(没有深入学习,只是基本操作):

 

代码
public static class UnityHelper
    {
        
/// <summary>
        
/// 通过Unity实组装对象泛型方法
        
/// </summary>
        
/// <typeparam name="T"></typeparam>
        
/// <param name="entity"></param>
        
/// <returns></returns>
        public static T UnityToT<T>(string name)
        {
            IUnityContainer container 
= CreateContainer();
            T model 
= container.Resolve<T>(name);
            
return model;
        }
        
/// <summary>
        
/// 通过Unity实组装对象泛型方法
        
/// </summary>
        
/// <typeparam name="T"></typeparam>
        
/// <param name="entity"></param>
        
/// <returns></returns>
        public static T UnityToT<T>()
        {
            IUnityContainer container 
= CreateContainer();
            T model 
= container.Resolve<T>();
            
return model;
        }
        
/// <summary>
        
/// 通过配置创建UnityContainer
        
/// </summary>
        
/// <returns></returns>
        public static IUnityContainer CreateContainer()
        {
            IUnityContainer container 
= new UnityContainer();
            UnityConfigurationSection section 
= (UnityConfigurationSection)
                System.Configuration.ConfigurationManager.GetSection(
"unity");
            section.Containers[
"Guestbook"].Configure(container);
            
return container;
        }
    }

 

 

CreateContainer就是创建UnityContainer,它是Unity的核心所在。通过它就可以进行动态组装了。这里可以用代码创建也可以通过配置文件。我选择配置文件。因为直接写代码里面侵入太强了,失去了很多灵活装配的意义。配置我直接写在了Web.config里面,也可以单独写配置文件。我们在后面讲一下配置文件。UnityToT(string name)是我写的一个泛型方法,通过name查找相应的配置项去组装并反回接口的对象,T是我们的接口。使用就如上面:private IGuestbookDal _guestbookDal = UnityHelper.UnityToT<IGuestbookDal>("DalType");,<IGuestbookDal>就是接口,我们在配置里面有指定。"DalType"就是配置的名称。下面我们看一下相关的配置项:

 

代码
<unity>
    
<containers>
      
<container name="Guestbook">
        
<types>
          
<type name="BizType" type="Guestbook.IBiz.IGuestbookBiz,Guestbook.IBiz" mapTo="Guestbook.Biz.GuestbookBiz,Guestbook.Biz"/>
          
<type name="DalType" type="Guestbook.IDal.IGuestbookDal,Guestbook.IDal" mapTo="Guestbook.Dal.GuestbookDal,Guestbook.dal"/>
        
</types>
      
</container>
    
</containers>
  
</unity>

 

 

type节就是我们的对应配置项,name是我们前面泛型方法要传入的name,type为接口,mapTo为具体的业务类。比如上面的IGuestbookDal持久层接口对应的相应的GuestbookDal持久类,这样配置后Unity就会帮我们根据接口装配(实例化)实现类,并反回相应的实例对象,我们就可以通过这个对象实现具体业务了,比如:_dao.Save(entity);。

 

这样我们的业务层也完成了,接下来就是UI层调用业务层就可以了。UI层我们一样通过Unity进行装配,UI层只引用实体类Guestbook.Model和Guestbook.IBiz业务层接口(当然用Unity要引用相应的UnityHelper类了)。这样UI层对业务层向下层次全部是弱依赖。UI我们基于的ASP.NET Mvc,所以我们在Controllers的里面进行业务层的装配并使用。我们以GuestbookInfo的列表显示为例,说一下。相应的Action叫说GuestbookList,代码如下:

 

代码
 private static IGuestbookBiz _biz = UnityHelper.UnityToT<IGuestbookBiz>("BizType");
        public ActionResult GuestbookList()
        {
            IList
<GuestbookInfo> guestbookList = _biz.GetList();
            return View(guestbookList);
        }

 

 private static IGuestbookBiz _biz = UnityHelper.UnityToT<IGuestbookBiz>("BizType");就是业务层装配了,我们通过业务接口IGuestbookBiz进行引用。通过_biz.GetList()就取得了相应的IList<GuestbookInfo>了。最后在相对应的View里面,指定Page Model ,像这样:Inherits="System.Web.Mvc.ViewPage<IList<Guestbook.Model.GuestbookInfo>>";然后在View中循环显示一下集合数据就可以了,大概像下面这样:

 

 

代码
 <%foreach(var item in Model){ %>
      
<table width="500" border="0" cellpadding="0" cellspacing="0">
      
<tr>
      
<th>姓名</th>
      
<th style="background-color:White"><%=item.GuestName %></th>
      
<th>性别</th>
      
<th style="background-color:White"><%=item.Sex==1?"":"" %></th>
      
</tr>
      
<tr>
      
<td colspan="4" height="50" valign="top">
      
<%=item.GuestMessage %>
      
</td>
      
</tr>
      
<tr>
      
<td colspan="4"><%=Html.ActionLink("删除","Delete",new{sysno=item.SysNo}) %></td>
      
</tr>
      
</table>
    
<%%>

 

 

最后放一张运行的图片,其它的Save,Delete方式其本相同,这里就不多讲了。大家可以在这里下载源码(已上传)。

 

 

posted @ 2010-07-16 23:27  Assion Yang  阅读(6154)  评论(50编辑  收藏  举报