前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码。之前的六篇完成了领域层、应用层、以及基础结构层的部分代码,这篇打算搭建下UI层的代码。

DDD领域驱动设计初探系列文章:

一、UI层介绍

在DDD里面,UI层的设计也分为BS和CS,本篇还是以Web为例来说明。我们的Web采用的是MVC+bootstrap的架构。Table组件使用的是bootstrap table,之所以用它是因为它的API比较全,并且博主觉得它的风格适用于各种类型的设备,无论是PC端还是手机端都都能很好的兼容各种浏览器。

这里还是贴出bootstrap API的相关地址。

Bootstrap中文网:http://www.bootcss.com/

Bootstrap Table Demo:http://issues.wenzhixin.net.cn/bootstrap-table/index.html

Bootstrap Table API:http://bootstrap-table.wenzhixin.net.cn/zh-cn/documentation/

Bootstrap Table源码:https://github.com/wenzhixin/bootstrap-table

Bootstrap DataPicker:http://www.bootcss.com/p/bootstrap-datetimepicker/

Bootstrap离线API

二、代码示例

上篇完成了WCF的设计代码,但是具体的业务逻辑的代码还没有,我们先来实现具体业务的CURD代码。

1、WCF代码

1.1 WCF服务业务接口代码

    /// <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
}

1.2 WCF接口实现代码:

 PowerManageWCFService

这里要说明一点,在通过lamada表达式查询的方法里面为什么不直接用Expression<Func<DTO_TB_USERS,bool>>这种类型,而要使用ExpressionNode这种类型的变量呢?

这是因为Expression不支持序列化,无法用于WCF数据的传递。ExpressionNode这个对象的使用需要添加Serialize.Linq这个dll的引用,还好有我们神奇的NuGet,让我们再也不用去网上找一大堆的dll了。

我们公用的增删改查封装到了BaseService这个父类里面。

1.3 BaseService代码

 BaseService

这个父类主要做了两件事:一是MEF的初始化;二是通用增删改查的实现。所有dto对象和领域model的映射都在这里统一管理。

2、UI层代码

UI层里面,为了更好分离代码,我们引入了接口编程的机制,引入了ESTM.Web.IBLL和ESTM.Web.BLL两个项目,如图:

为什么要有这么一个接口层?之前C#进阶系列——MEF实现设计上的“松耦合”(终结篇:面向接口编程)这篇已经做过介绍,对面向接口编程不了解的朋友可以看看。

2.1 ESTM.Web.IBLL代码

这个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); }

2.2 ESTM.Web.BLL代码

这个dll用于实现ESTM.Web.IBLL里面的接口方法

 PowerManager : IPowerManager
  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的内容,那么我们就需要更新下服务引用。还好,微软给我们选择的机制,我们来看图

这样就能解决上面的问题了。

2.3 ESTM.Web代码

按照面向接口的机制,ESTM.Web项目是不需要添加ESTM.Web.BLL这个实现层项目引用的,通过MEF动态导入ESTM.Web.BLL里面的对象。我们来看代码:

 PowerManagerController

View页面

 _Layout.cshtml
 Department.cshtml

JS代码我们来看一个页面就好了,其他页面类似:

 DepartmentManage.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界面好看,在这里将源码分享出来,当然这里的代码肯定也不太全,很多没实现的功能还需要自己去实现,但是基本的架子搭起来了,有兴趣可以看看。源码下载

DDD领域驱动设计初探(七):Web层的搭建的更多相关文章

  1. C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建

    前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码.之前的六篇完成了领域层.应用层.以及基础结构层的部分代码,这篇打算搭建下UI层的代码. DDD领域驱动设计初 ...

  2. C#进阶系列——DDD领域驱动设计初探(一):聚合

    前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...

  3. C#进阶系列——DDD领域驱动设计初探(二):仓储Repository(上)

    前言:上篇介绍了DDD设计Demo里面的聚合划分以及实体和聚合根的设计,这章继续来说说DDD里面最具争议的话题之一的仓储Repository,为什么Repository会有这么大的争议,博主认为主要原 ...

  4. C#进阶系列——DDD领域驱动设计初探(三):仓储Repository(下)

    前言:上篇介绍了下仓储的代码架构示例以及简单分析了仓储了使用优势.本章还是继续来完善下仓储的设计.上章说了,仓储的最主要作用的分离领域层和具体的技术架构,使得领域层更加专注领域逻辑.那么涉及到具体的实 ...

  5. C#进阶系列——DDD领域驱动设计初探(四):WCF搭建

    前言:前面三篇分享了下DDD里面的两个主要特性:聚合和仓储.领域层的搭建基本完成,当然还涉及到领域事件和领域服务的部分,后面再项目搭建的过程中慢慢引入,博主的思路是先将整个架构走通,然后一步一步来添加 ...

  6. C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用

    前言:前篇搭建了下WCF的代码,就提到了DTO的概念,对于为什么要有这么一个DTO的对象,上章可能对于这点不太详尽,在此不厌其烦再来提提它的作用: 从安全上面考虑,领域Model都带有领域业务,让Cl ...

  7. C#进阶系列——DDD领域驱动设计初探(六):领域服务

    前言:之前一直在搭建项目架构的代码,有点偏离我们的主题(DDD)了,这篇我们继续来聊聊DDD里面另一个比较重要的知识点:领域服务.关于领域服务的使用,书中也介绍得比较晦涩,在此就根据博主自己的理解谈谈 ...

  8. DDD领域驱动设计初探(六):领域服务

    前言:之前一直在搭建项目架构的代码,有点偏离我们的主题(DDD)了,这篇我们继续来聊聊DDD里面另一个比较重要的知识点:领域服务.关于领域服务的使用,书中也介绍得比较晦涩,在此就根据博主自己的理解谈谈 ...

  9. DDD领域驱动设计初探(五):AutoMapper使用

    前言:前篇搭建了下WCF的代码,就提到了DTO的概念,对于为什么要有这么一个DTO的对象,上章可能对于这点不太详尽,在此不厌其烦再来提提它的作用: 从安全上面考虑,领域Model都带有领域业务,让Cl ...

随机推荐

  1. curl下载文件时自动创建目录

    有时候需要自动创建多级目录 按照如下格式即可 curl -o d:/lei/demo/test.jpg --create-dirs http://img.7160.com/uploads/allimg ...

  2. 使用MingGW-w64 Build Script 3.6.7搭建ffmpeg编译环境

    在Linux下编译的Windows版本ffmpeg没有其他的依赖库 使用的是centos 1.脚本下载 wget http://zeranoe.com/scripts/mingw_w64_build/ ...

  3. between()函数

    1 between函数返回一个布尔量,即如果在该范围内,返回True,否则返回False. 注意between()中括号内是左闭右闭区间 在dataframe中常可用来通过选择某一列元素的范围来选择另 ...

  4. php7.2 下安装swoole扩展

    git clone git@github.com:swoole/swoole-src.git phpize ./configure make && make test make ins ...

  5. 一文学会Rust?

    Rust是什么 Rust 是一个系统编程语言,它注重三个方面:安全,速度和并发性. 特征: 1.没有垃圾回收机制,没有运行时,效率超过c++,直逼c语言 2.内存安全,并发安全,没有空指针 3.极其丰 ...

  6. CSS3——注释 id 和 class 选择器 css创建(外部、内部、内联样式表)

    注释 /*         注释内容          */ id 和 class 选择器 id   ID属性不要以数字开头,数字开头的ID在 Mozilla/Firefox 浏览器中不起作用 < ...

  7. 【ABAP系列】SAP ABAP 从FTP服务器读取文件到本地

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 从FTP服务器 ...

  8. vue仿阿里云后台管理(附加阿里巴巴图标使用)

    先看下页面截图,在线演示地址http://aliadmin.zengjielin.top 下面有开源的代码 页面分成三大部分头部,头部菜单栏,侧边菜单栏,右侧内容栏. 现在我们担心的是怎么使用侧边栏. ...

  9. django中使用原生的orm

    只有用的时候才能执行

  10. [CF585E]Marbles

    Description: 给定一个序列 \(a_i\) ,每次可以交换相邻两个元素,求使序列变成若干个极大连续段,每个极大连续段内部的值相同且任意两个极大连续段的值互不相同. \(n\le 4\tim ...