前言:很久没更新博客了,天天被该死的业务缠身,今天正好一个模块完成了,继续来完善咱们的代码。以前的六篇完成了领域层、应用层、以及基础结构层的部分代码,这篇打算搭建下UI层的代码。css
DDD领域驱动设计初探系列文章:html
在DDD里面,UI层的设计也分为BS和CS,本篇仍是以Web为例来讲明。咱们的Web采用的是MVC+bootstrap的架构。Table组件使用的是bootstrap table,之因此用它是由于它的API比较全,而且博主以为它的风格适用于各类类型的设备,不管是PC端仍是手机端都都能很好的兼容各类浏览器。前端
这里仍是贴出bootstrap API的相关地址。git
Bootstrap中文网:http://www.bootcss.com/ github
Bootstrap Table Demo:http://issues.wenzhixin.net.cn/bootstrap-table/index.htmlexpress
Bootstrap Table API:http://bootstrap-table.wenzhixin.net.cn/zh-cn/documentation/编程
Bootstrap Table源码:https://github.com/wenzhixin/bootstrap-tablebootstrap
Bootstrap DataPicker:http://www.bootcss.com/p/bootstrap-datetimepicker/浏览器
上篇完成了WCF的设计代码,可是具体的业务逻辑的代码尚未,咱们先来实现具体业务的CURD代码。
/// <summary> /// 权限管理模块接口契约 /// </summary> [ServiceContract] [ServiceInterface] public interface IPowerManageWCFService { #region 用户管理 [OperationContract] List<DTO_TB_USERS> GetUsers(ExpressionNode expressionNode); [OperationContract] DTO_TB_USERS AddUser(DTO_TB_USERS oUser); [OperationContract] bool DeleteUser(DTO_TB_USERS oUser); [OperationContract] bool DeleteUserByLamada(ExpressionNode expressionNode); [OperationContract] bool UpdateUser(DTO_TB_USERS oUser); #endregion #region 部门管理 [OperationContract] List<DTO_TB_DEPARTMENT> GetDepartments(ExpressionNode expressionNode); [OperationContract] DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept); [OperationContract] bool DeleteDepartment(DTO_TB_DEPARTMENT oDept); [OperationContract] bool DeleteDeptByLamada(ExpressionNode expressionNode); [OperationContract] bool UpdateDepartment(DTO_TB_DEPARTMENT oDept); #endregion #region 角色管理 [OperationContract] List<DTO_TB_ROLE> GetRoles(ExpressionNode expressionNode); [OperationContract] DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole); #endregion #region 菜单管理 [OperationContract] List<DTO_TB_MENU> GetMenus(ExpressionNode expressionNode); [OperationContract] DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu); #endregion }
这里要说明一点,在经过lamada表达式查询的方法里面为何不直接用Expression<Func<DTO_TB_USERS,bool>>这种类型,而要使用ExpressionNode这种类型的变量呢?
这是由于Expression不支持序列化,没法用于WCF数据的传递。ExpressionNode这个对象的使用须要添加Serialize.Linq这个dll的引用,还好有咱们神奇的NuGet,让咱们不再用去网上找一大堆的dll了。
咱们公用的增删改查封装到了BaseService这个父类里面。
这个父类主要作了两件事:一是MEF的初始化;二是通用增删改查的实现。全部dto对象和领域model的映射都在这里统一管理。
UI层里面,为了更好分离代码,咱们引入了接口编程的机制,引入了ESTM.Web.IBLL和ESTM.Web.BLL两个项目,如图:
为何要有这么一个接口层?以前C#进阶系列——MEF实现设计上的“松耦合”(终结篇:面向接口编程)这篇已经作过介绍,对面向接口编程不了解的朋友能够看看。
这个dll主要定义接口规则。
public interface IPowerManager { List<DTO_TB_USERS> GetUsers(Expression<Func<DTO_TB_USERS, bool>> selector = null); DTO_TB_USERS AddUser(DTO_TB_USERS oUser); bool DeleteUser(DTO_TB_USERS oUser); bool UpdateUser(DTO_TB_USERS oUser); bool DeleteUser(Expression<Func<DTO_TB_USERS, bool>> selector = null); List<DTO_TB_DEPARTMENT> GetDepartments(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null); DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept); bool DeleteDepartment(DTO_TB_DEPARTMENT oDept); bool DeleteDepartment(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null); bool UpdateDepartment(DTO_TB_DEPARTMENT oDept); List<DTO_TB_ROLE> GetRoles(Expression<Func<DTO_TB_ROLE, bool>> selector = null); List<DTO_TB_MENU> GetMenus(Expression<Func<DTO_TB_MENU, bool>> selector = null); }
这个dll用于实现ESTM.Web.IBLL里面的接口方法
public class CreatePowerManagerService { private static ServiceReference_PowerManager.PowerManageWCFServiceClient oPowerManagerClient = null; private static object obj = new object(); public static ServiceReference_PowerManager.PowerManageWCFServiceClient GetInstance() { lock (obj) { if (oPowerManagerClient == null) { oPowerManagerClient = new ServiceReference_PowerManager.PowerManageWCFServiceClient(); } } return oPowerManagerClient; } }
因为是采用的添加服务引用的方式引用的WCF服务,因此在这一层须要添加WCF服务的引用。在实现这部分代码的时候博主遇到过一个问题,在此和朋友们分享一下。因为在WCF服务的设计里面用到了DTO对象,而在ESTM.Web.BLL这个项目里面也要用到DTO,可是添加WCF服务引用的时候默认的是WCF服务里面的DTO,而不是ESTM.Common.DtoModel这个项目的DTO对象,这样就有问题了,每次若是咱们须要改动下dto的内容,那么咱们就须要更新下服务引用。还好,微软给咱们选择的机制,咱们来看图
这样就能解决上面的问题了。
按照面向接口的机制,ESTM.Web项目是不须要添加ESTM.Web.BLL这个实现层项目引用的,经过MEF动态导入ESTM.Web.BLL里面的对象。咱们来看代码:
View页面
JS代码咱们来看一个页面就行了,其余页面相似:
效果图:
在作页面数据更新的时候,博主又遇到一个问题:ObjectStateManager 中已存在具备同一键的对象。ObjectStateManager 没法跟踪具备相同键的多个对象。在此仍是记录下解决方案:
在仓储的公共实现类中将
public virtual IQueryable<TEntity> Entities { get { return UnitOfWork.context.Set<TEntity>(); } }
改为
public virtual IQueryable<TEntity> Entities { get { return UnitOfWork.context.Set<TEntity>().AsNoTracking() as IQueryable<TEntity>; } }
就能够了。
至此,从领域模型到Web前端的代码基本完成,可能不少代码并未完善,好比异常处理、数据验证等。以前写过一篇CS版本的权限系统 系统设计——权限系统,不少朋友找我要过源码,那个时候可能代码都在工做的项目中,没办法抽离出来,在此表示抱歉。如今作了一个BS的,感受BS比CS界面好看,在这里将源码分享出来,固然这里的代码确定也不太全,不少没实现的功能还须要本身去实现,可是基本的架子搭起来了,有兴趣能够看看。源码下载