您的位置:首页 > 编程语言 > ASP

(转)一步一步Asp.Net MVC系列_权限管理设计起始篇

2012-08-10 17:34 459 查看
原文地址:http://www.cnblogs.com/mysweet/archive/2012/07/26/2610793.html

前一段时间,写了一步一步asp.net的一系列博客,最近,也快要大四,忙着准备找个工作,这也算是最后一个假期了,这个系列可能不太长,尽量写完.还是多学习,少扯淡的风格,我们的学习还好

继续,现在开始学习asp.netMVC系列,基础知识,大家看博客园相关的一系列就可以了,我们在

这里学一下一个权限管理的设计.我采用的是Asp.netMVC+EF+N层的方式,顺便加入点

spring.net注入的部分,当然我们最主要的还是关于权限设计的部分.而架构,咱也没学过太复

杂的架构,我们还是从最常用的三层架构进行扩展.

参考书籍:

<<重构,改善既有代码的设计>>

<<.net应用架构设计原则,模式与实践>>

<<.net设计范式>>

<<代码整洁之道>>

以及网上众多的教程,博客等等

首先,我们要讲解一下关于项目的搭建部分.我们的项目主要分为5部分,业务逻辑层,数据访问层,界面层,领域模型层以及

一个公共类的部分.

当然,我们要先建立一个工程,并建立相应的解决方案文件夹,并且保持清晰程度,我们在工程加上前缀(最好是公司前缀)后面加上部分.





然后在每个解决方案文件夹下面建立响应的项目,





这里主要是:

业务逻辑层:

TZHSWEET.IBLL:业务逻辑层接口

TZHSWEET.BLL:业务逻辑层实现

数据访问层:

TZHSWEET.IDao:数据访问层接口

TZHSWEET.Dao:数据访问层实现

领域模型层:

TZHSWEET.Entity:这是EF建立的模型

TZHSWEET.ViewModel:这个是用来传递UI层和业务逻辑层的相关模型对象

界面层:

TZHSWEET.WebUI:主要的MVC和LigerUI实现的界面部分

TZHSWEET.UI:关于MVC公共UI定义的部分

公共类库部分:

TZHSWEET.CacheStorage主要是常用的缓存

TZHSWEET.Common主要是一些公共类实现等等

这里仅仅是三层架构按照我自己的想法做了一个适应性扩展,呵呵.

EF不用说了,这里只是一个简单的应用





在这里我先讲解关于Idao和Dao部分

我们的目标是"0"增删改查的数据访问层实现,

主要是靠EF的定义通用的增删改查,然后其他类继承增删改查接口和相应的自定义子类接口,实现扩展.

首先,我们从以前写代码的经验知道,我们的Dao主要是做增删改查等方面,我们就先定义一个公共的接口,叫做IBaseDao,这个接口定义泛型的增删改查,

/*作者:tianzh
*创建时间:2012/7/1611:01:34
*
*/
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingSystem.Data.Objects;
namespaceTZHSWEET.IDao
{
publicinterfaceIBaseDao<T>//whereT:class//限制class
{
#region查询普通实现方案(基于Lambda表达式的Where查询)
///<summary>
///获取所有Entity
///</summary>
///<paramname="exp">Lambda条件的where</param>
///<returns></returns>
IEnumerable<T>GetEntities(Func<T,bool>exp);
///<summary>
///计算总个数(分页)
///</summary>
///<paramname="exp">Lambda条件的where</param>
///<returns></returns>
intGetEntitiesCount(Func<T,bool>exp);
///<summary>
///分页查询(Linq分页方式)
///</summary>
///<paramname="pageNumber">当前页</param>
///<paramname="pageSize">页码</param>
///<paramname="orderName">lambda排序名称</param>
///<paramname="sortOrder">排序(升序or降序)</param>
///<paramname="exp">lambda查询条件where</param>
///<returns></returns>
IEnumerable<T>GetEntitiesForPaging(intpageNumber,intpageSize,Func<T,string>orderName,stringsortOrder,Func<T,bool>exp);
///<summary>
///根据条件查找
///</summary>
///<paramname="exp">lambda查询条件where</param>
///<returns></returns>
TGetEntity(Func<T,bool>exp);
#endregion
#region查询Sql语句外接接口的查询实现
///<summary>
///获取所有Entity(立即执行请使用ToList()
///</summary>
///<paramname="CommandText">Sql语句</param>
///<paramname="objParams">可变参数</param>
///<returns></returns>
IEnumerable<T>GetEntities(stringCommandText);
///<summary>
///计算总个数(分页)
///</summary>
///<paramname="CommandText">Sql语句</param>
///<paramname="objParams">可变参数</param>
///<returns></returns>
intGetEntitiesCount(stringCommandText);
///<summary>
///分页查询(Linq分页方式)
///</summary>
///<paramname="tableName">表名</param>
///<paramname="pageNumber">当前页</param>
///<paramname="pageSize">页码</param>
///<paramname="orderName">lambda排序名称</param>
///<paramname="sortOrder">排序(升序or降序)</param>
///<paramname="CommandText">Sql语句</param>
///<paramname="Count">总个数</param>
///<returns></returns>
IEnumerable<T>GetEntitiesForPaging(stringtableName,intpageNumber,intpageSize,stringorderName,stringsortOrder,stringCommandText,outintCount);
///<summary>
///根据条件查找
///</summary>
///<paramname="CommandText">Sql语句</param>
///<paramname="objParams">可变参数</param>
///<returns></returns>
TGetEntity(stringCommandText);
#endregion
///<summary>
///插入Entity
///</summary>
///<paramname="model"></param>
///<returns></returns>
boolInsert(Tentity);
///<summary>
///更新Entity
///</summary>
///<paramname="model"></param>
///<returns></returns>
boolUpdate(Tentity);
///<summary>
///删除Entity
///</summary>
///<paramname="entity"></param>
///<returns></returns>
boolDelete(Tentity);
}
}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
接下来,我们需要定义一系列的接口继承这个接口,代码类似:

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingTZHSWEET.Entity;
namespaceTZHSWEET.IDao
{
publicinterfaceIDepartmentDao<T>:IBaseDao<T>whereT:class
{
}
}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
这层接口,大家可能认为没什么必要,但是,这个接口非常重要,这个接口保证了我们用EF一个抽象类实现增删改查的同时又增加了子类的自身扩展性.

接下来,就是Dao部分,我们需要很慎重的去设计,

首先我们要设计一个用EF实现的公共父类的BaseEFDao类,用他来实现增删改查,

/*作者:tianzh
*创建时间:2012/7/1611:06:16
*
*/
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingTZHSWEET.IDao;
usingTZHSWEET.Entity;
usingSystem.Data;
usingTZHSWEET.Common;
usingSystem.Data.Objects;
namespaceTZHSWEET.EFDao
{
///<summary>
///公共接口
///</summary>
publicclassBaseEFDao<T>:IBaseDao<T>whereT:class,new()//限制T为class
{
#region查询普通实现方案(基于Lambda表达式的Where查询)
///<summary>
///获取所有Entity
///</summary>
///<paramname="exp">Lambda条件的where</param>
///<returns></returns>
publicvirtualIEnumerable<T>GetEntities(Func<T,bool>exp)
{
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
returnEntities.CreateObjectSet<T>().Where(exp).ToList();
}
}
///<summary>
///计算总个数(分页)
///</summary>
///<paramname="exp">Lambda条件的where</param>
///<returns></returns>
publicvirtualintGetEntitiesCount(Func<T,bool>exp)
{
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
returnEntities.CreateObjectSet<T>().Where(exp).Count();
}
}
///<summary>
///分页查询(Linq分页方式)
///</summary>
///<paramname="pageNumber">当前页</param>
///<paramname="pageSize">页码</param>
///<paramname="orderName">lambda排序名称</param>
///<paramname="sortOrder">排序(升序or降序)</param>
///<paramname="exp">lambda查询条件where</param>
///<returns></returns>
publicvirtualIEnumerable<T>GetEntitiesForPaging(intpageNumber,intpageSize,Func<T,string>orderName,stringsortOrder,Func<T,bool>exp)
{
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
if(sortOrder=="asc")//升序排列
{
returnEntities.CreateObjectSet<T>().Where(exp).OrderBy(orderName).Skip((pageNumber-1)*pageSize).Take(pageSize).ToList();
}
else
returnEntities.CreateObjectSet<T>().Where(exp).OrderByDescending(orderName).Skip((pageNumber-1)*pageSize).Take(pageSize).ToList();
}
}
///<summary>
///根据条件查找
///</summary>
///<paramname="exp">lambda查询条件where</param>
///<returns></returns>
publicvirtualTGetEntity(Func<T,bool>exp)
{
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
returnEntities.CreateObjectSet<T>().Where(exp).SingleOrDefault();
}
}
#endregion
#region查询EntityToSql语句外接接口的查询实现
///<summary>
///获取所有Entity(立即执行请使用ToList()
///</summary>
///<paramname="CommandText">Sql语句</param>
///<paramname="objParams">可变参数</param>
///<returns></returns>
publicvirtualIEnumerable<T>GetEntities(stringCommandText)
{
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
returnEntities.ExecuteStoreQuery<T>("select*from"+typeof(T).Name+"where"+CommandText).ToList();
}
}
///<summary>
///计算总个数(分页)
///</summary>
///<paramname="CommandText">Sql语句</param>
///<returns></returns>
publicvirtualintGetEntitiesCount(stringCommandText)
{
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
returnEntities.ExecuteStoreQuery<T>("select*from"+typeof(T).Name+"where"+CommandText).Count();
}
}
///<summary>
///分页查询(Linq分页方式)
///</summary>
///<paramname="tableName">表名</param>
///<paramname="pageNumber">当前页</param>
///<paramname="pageSize">页码</param>
///<paramname="orderName">lambda排序名称</param>
///<paramname="sortOrder">排序(升序or降序)</param>
///<paramname="CommandText">Sql语句</param>
///<paramname="Count">总个数</param>
///<returns></returns>
publicvirtualIEnumerable<T>GetEntitiesForPaging(stringtableName,intpageNumber,intpageSize,stringorderName,stringsortOrder,stringCommandText,outintCount)
{
PaginationHelperpager=newPaginationHelper(tableName,orderName,pageSize,pageNumber,sortOrder,CommandText);
pager.GetSelectTopByMaxOrMinPagination();
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
Count=GetEntitiesCount(CommandText);
returnEntities.ExecuteStoreQuery<T>(pager.GetSelectTopByMaxOrMinPagination()).ToList();
}
}
///<summary>
///根据条件查找
///</summary>
///<paramname="CommandText">Sql语句</param>
///<paramname="objParams">可变参数</param>
///<returns></returns>
publicvirtualTGetEntity(stringCommandText)
{
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
returnEntities.ExecuteStoreQuery<T>("select*from"+typeof(T).Name+"where"+CommandText).SingleOrDefault();
}
}
#endregion
#region增删改实现
///<summary>
///插入Entity
///</summary>
///<paramname="model"></param>
///<returns></returns>
publicvirtualboolInsert(Tentity)
{
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
varobj=Entities.CreateObjectSet<T>();
obj.AddObject(entity);
returnEntities.SaveChanges()>0;
}
}
///<summary>
///更新Entity(注意这里使用的傻瓜式更新,可能性能略低)
///</summary>
///<paramname="model"></param>
///<returns></returns>
publicvirtualboolUpdate(Tentity)
{
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
varobj=Entities.CreateObjectSet<T>();
obj.Attach(entity);
Entities.ObjectStateManager.ChangeObjectState(entity,EntityState.Modified);
returnEntities.SaveChanges()>0;
}
}
///<summary>
///删除Entity
///</summary>
///<paramname="entity"></param>
///<returns></returns>
publicvirtualboolDelete(Tentity)
{
using(BaseManageEntitiesEntities=newBaseManageEntities())
{
varobj=Entities.CreateObjectSet<T>();
if(entity!=null)
{
obj.Attach(entity);
Entities.ObjectStateManager.ChangeObjectState(entity,EntityState.Deleted);
obj.DeleteObject(entity);
returnEntities.SaveChanges()>0;
}
returnfalse;
}
}
#endregion
}
}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

接下来我们的工作量就小了,我们可以看到成果了,我们接下来的实现,只需要继承上面这个BaseEFDao和IxxxDao的部分就可以很轻松的实现,子类的增删改查以及子类的扩展了.

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
usingTZHSWEET.Entity;
usingTZHSWEET.IDao;
namespaceTZHSWEET.EFDao
{
publicclassFavoriteEFDao:BaseEFDao<tbFavorite>,IFavoriteDao<tbFavorite>
{
}
}


.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
大家可以看到继承了2个,一个是BaseEFDao父类,一个是IFavoriteDao接口,

BaseEFDao是实现EF的增删改查,IFavoriteDao实现了子类的扩展,比如子类需要加入

GetxxxByID之类的,当然我们在业务逻辑层一般只能通过IFavoriteDao调用此服务,而

这个继承体系保证了我们在实现增删改查的同时外放一个接口保证扩展性.

继承体系图:





这样我们的数据访问层,很轻松的实现了,基本上代码量非常少,增删改查部分几乎"0"代码,都是泛型的父类实现了.

今天就讲解到这里,接下来插播点当前有趣的实例部分:





界面友好,友好的名称远远比注释更好,<<重构>>这本书,让我学到太多太多,特别是细节的设计,更清晰.

可以参考,我的代码风格,可以看到我的进步非常大,我现在看到2-3个月以前的代码,简直都是<<重构>>这本书的反面教材.

当前的权限管理系统,设计了一个初步的模型,这里贴张小图:

参考了LigerUI,谢略的权限管理系统,吉日的权限管理数据库设计和N多日志,以及传说中的弦哥的Asp.Net大型项目实践系列教程,以及众多的资料,慢慢的我也会把这个写成一个系列.最后,写完这个教程,我会把代码传到公共网盘上面,不过由于现在代码持续改进,所以,就大家先看看思路.



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: