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

  1. /// <summary>
  2. /// 权限管理模块接口契约
  3. /// </summary>
  4. [ServiceContract]
  5. [ServiceInterface]
  6. public interface IPowerManageWCFService
  7. {
  8.  
  9. #region 用户管理
  10. [OperationContract]
  11. List<DTO_TB_USERS> GetUsers(ExpressionNode expressionNode);
  12.  
  13. [OperationContract]
  14. DTO_TB_USERS AddUser(DTO_TB_USERS oUser);
  15.  
  16. [OperationContract]
  17. bool DeleteUser(DTO_TB_USERS oUser);
  18.  
  19. [OperationContract]
  20. bool DeleteUserByLamada(ExpressionNode expressionNode);
  21.  
  22. [OperationContract]
  23. bool UpdateUser(DTO_TB_USERS oUser);
  24. #endregion
  25.  
  26. #region 部门管理
  27. [OperationContract]
  28. List<DTO_TB_DEPARTMENT> GetDepartments(ExpressionNode expressionNode);
  29.  
  30. [OperationContract]
  31. DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept);
  32.  
  33. [OperationContract]
  34. bool DeleteDepartment(DTO_TB_DEPARTMENT oDept);
  35.  
  36. [OperationContract]
  37. bool DeleteDeptByLamada(ExpressionNode expressionNode);
  38.  
  39. [OperationContract]
  40. bool UpdateDepartment(DTO_TB_DEPARTMENT oDept);
  41. #endregion
  42.  
  43. #region 角色管理
  44. [OperationContract]
  45. List<DTO_TB_ROLE> GetRoles(ExpressionNode expressionNode);
  46.  
  47. [OperationContract]
  48. DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole);
  49. #endregion
  50.  
  51. #region 菜单管理
  52. [OperationContract]
  53. List<DTO_TB_MENU> GetMenus(ExpressionNode expressionNode);
  54.  
  55. [OperationContract]
  56. DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu);
  57. #endregion
  58. }

1.2 WCF接口实现代码:

  1. [ServiceClass]
  2. public class PowerManageWCFService :BaseService, IPowerManageWCFService
  3. {
  4. #region Fields
  5. [Import]
  6. private IUserRepository userRepository { get; set; }
  7.  
  8. [Import]
  9. private IDepartmentRepository departmentRepository { get; set; }
  10.  
  11. [Import]
  12. private IRoleRepository roleRepository { get; set; }
  13.  
  14. [Import]
  15. private IMenuRepository menuRepository { get; set; }
  16. #endregion
  17.  
  18. #region Constust
  19. public PowerManageWCFService()
  20. {
  21.  
  22. }
  23. #endregion
  24.  
  25. #region WCF服务接口实现
  26. #region 用户管理
  27. //这里参数为什么不直接用Expression<Func<DTO_TB_USERS,bool>>这种类型,是因为Expression不支持序列化,无法用于WCF数据的传递
  28. public List<DTO_TB_USERS> GetUsers(ExpressionNode expressionNode)
  29. {
  30. Expression<Func<DTO_TB_USERS, bool>> selector = null;
  31. if (expressionNode != null)
  32. {
  33. selector = expressionNode.ToExpression<Func<DTO_TB_USERS, bool>>();
  34. }
  35. var lstRes = base.GetDtoByLamada<DTO_TB_USERS, TB_USERS>(userRepository, selector);
  36. return lstRes;
  37. }
  38.  
  39. public DTO_TB_USERS AddUser(DTO_TB_USERS oUser)
  40. {
  41. return base.AddDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser);
  42. }
  43.  
  44. public bool DeleteUser(DTO_TB_USERS oUser)
  45. {
  46. var bRes = false;
  47. try
  48. {
  49. base.DeleteDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser);
  50. bRes = true;
  51. }
  52. catch
  53. {
  54.  
  55. }
  56. return bRes;
  57. }
  58.  
  59. public bool DeleteUserByLamada(ExpressionNode expressionNode)
  60. {
  61. Expression<Func<DTO_TB_USERS, bool>> selector = null;
  62. if (expressionNode != null)
  63. {
  64. selector = expressionNode.ToExpression<Func<DTO_TB_USERS, bool>>();
  65. }
  66. var bRes = false;
  67. try
  68. {
  69. base.DeleteDto<DTO_TB_USERS, TB_USERS>(userRepository, selector);
  70. bRes = true;
  71. }
  72. catch
  73. {
  74.  
  75. }
  76. return bRes;
  77. }
  78.  
  79. public bool UpdateUser(DTO_TB_USERS oUser)
  80. {
  81. var bRes = false;
  82. try
  83. {
  84. base.UpdateDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser);
  85. bRes = true;
  86. }
  87. catch
  88. {
  89.  
  90. }
  91. return bRes;
  92. }
  93. #endregion
  94.  
  95. #region 部门管理
  96. public List<DTO_TB_DEPARTMENT> GetDepartments(ExpressionNode expressionNode)
  97. {
  98. Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null;
  99. if (expressionNode != null)
  100. {
  101. selector = expressionNode.ToExpression<Func<DTO_TB_DEPARTMENT, bool>>();
  102. }
  103. return base.GetDtoByLamada<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, selector);
  104. }
  105. public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept)
  106. {
  107. return base.AddDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept);
  108. }
  109.  
  110. public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept)
  111. {
  112. var bRes = false;
  113. try
  114. {
  115. base.DeleteDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept);
  116. bRes = true;
  117. }
  118. catch
  119. {
  120.  
  121. }
  122. return bRes;
  123. }
  124.  
  125. public bool DeleteDeptByLamada(ExpressionNode expressionNode)
  126. {
  127. Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null;
  128. if (expressionNode != null)
  129. {
  130. selector = expressionNode.ToExpression<Func<DTO_TB_DEPARTMENT, bool>>();
  131. }
  132. var bRes = false;
  133. try
  134. {
  135. base.DeleteDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, selector);
  136. bRes = true;
  137. }
  138. catch
  139. {
  140.  
  141. }
  142. return bRes;
  143. }
  144.  
  145. public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept)
  146. {
  147. var bRes = false;
  148. try
  149. {
  150. base.UpdateDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept);
  151. bRes = true;
  152. }
  153. catch
  154. {
  155.  
  156. }
  157. return bRes;
  158. }
  159. #endregion
  160.  
  161. #region 角色管理
  162. public List<DTO_TB_ROLE> GetRoles(ExpressionNode expressionNode)
  163. {
  164. Expression<Func<DTO_TB_ROLE, bool>> selector = null;
  165. if (expressionNode != null)
  166. {
  167. selector = expressionNode.ToExpression<Func<DTO_TB_ROLE, bool>>();
  168. }
  169. return base.GetDtoByLamada<DTO_TB_ROLE, TB_ROLE>(roleRepository, selector);
  170. }
  171.  
  172. public DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole)
  173. {
  174. return base.AddDto<DTO_TB_ROLE, TB_ROLE>(roleRepository, oRole);
  175. }
  176. #endregion
  177.  
  178. #region 菜单管理
  179. public List<DTO_TB_MENU> GetMenus(ExpressionNode expressionNode)
  180. {
  181. Expression<Func<DTO_TB_MENU, bool>> selector = null;
  182. if (expressionNode != null)
  183. {
  184. selector = expressionNode.ToExpression<Func<DTO_TB_MENU, bool>>();
  185. }
  186. return base.GetDtoByLamada<DTO_TB_MENU, TB_MENU>(menuRepository, selector);
  187. }
  188.  
  189. public DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu)
  190. {
  191. return base.AddDto<DTO_TB_MENU, TB_MENU>(menuRepository, oMenu);
  192. }
  193. #endregion
  194. #endregion
  195. }

PowerManageWCFService

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

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

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

1.3 BaseService代码

  1. public class BaseService
  2. {
  3. #region Fields
  4. private bool bInitAutoMapper = false;
  5. #endregion
  6.  
  7. #region Construct
  8. public BaseService()
  9. {
  10. //注册MEF
  11. Regisgter.regisgter().ComposeParts(this);
  12. }
  13. #endregion
  14.  
  15. #region 查询
  16. /// <summary>
  17. /// 通用单表查询方法
  18. /// </summary>
  19. /// <typeparam name="DtoModel">DTOmodel</typeparam>
  20. /// <typeparam name="DomainModel">领域模型</typeparam>
  21. /// <param name="oRepository">需要传过来的仓储接口对象</param>
  22. /// <param name="selector">前端传过来的lamada表达式</param>
  23. /// <returns></returns>
  24. public List<DtoModel> GetDtoByLamada<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, Expression<Func<DtoModel, bool>> selector = null)
  25. where DomainModel : AggregateRoot
  26. where DtoModel : Dto_BaseModel
  27. {
  28. InitAutoMapper<DtoModel, DomainModel>();
  29. if (selector == null)
  30. {
  31. var lstDomainModel = oRepository.Entities.ToList();
  32. return Mapper.Map<List<DomainModel>, List<DtoModel>>(lstDomainModel);
  33. }
  34. //得到从Web传过来和DTOModel相关的lamaba表达式的委托
  35. Func<DtoModel, bool> match = selector.Compile();
  36. //创建映射Expression的委托
  37. Func<DomainModel, DtoModel> mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression<DomainModel, DtoModel>(Mapper.Engine).Compile();
  38. //得到领域Model相关的lamada
  39. Expression<Func<DomainModel, bool>> lamada = ef_t => match(mapper(ef_t));
  40. List<DomainModel> list = oRepository.Find(lamada).ToList();
  41. return Mapper.Map<List<DomainModel>, List<DtoModel>>(list);
  42. }
  43. #endregion
  44.  
  45. #region 新增
  46. public DtoModel AddDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel)
  47. where DomainModel : AggregateRoot
  48. where DtoModel : Dto_BaseModel
  49. {
  50. InitAutoMapper<DtoModel, DomainModel>();
  51. var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel);
  52. oRepository.Insert(oDomain);
  53. return Mapper.Map<DomainModel, DtoModel>(oDomain);
  54. }
  55. #endregion
  56.  
  57. #region 删除
  58. public int DeleteDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel)
  59. where DomainModel : AggregateRoot
  60. where DtoModel : Dto_BaseModel
  61. {
  62. InitAutoMapper<DtoModel, DomainModel>();
  63. var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel);
  64. return oRepository.Delete(oDomain);
  65. }
  66.  
  67. public int DeleteDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, Expression<Func<DtoModel, bool>> selector = null)
  68. where DomainModel : AggregateRoot
  69. where DtoModel : Dto_BaseModel
  70. {
  71. InitAutoMapper<DtoModel, DomainModel>();
  72. if (selector == null)
  73. {
  74. return ;
  75. }
  76. //得到从Web传过来和DTOModel相关的lamaba表达式的委托
  77. Func<DtoModel, bool> match = selector.Compile();
  78. //创建映射Expression的委托
  79. Func<DomainModel, DtoModel> mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression<DomainModel, DtoModel>(Mapper.Engine).Compile();
  80. //得到领域Model相关的lamada
  81. Expression<Func<DomainModel, bool>> lamada = ef_t => match(mapper(ef_t));
  82. return oRepository.Delete(lamada);
  83. }
  84. #endregion
  85.  
  86. #region 更新
  87. public void UpdateDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel)
  88. where DomainModel : AggregateRoot
  89. where DtoModel : Dto_BaseModel
  90. {
  91. InitAutoMapper<DtoModel, DomainModel>();
  92. var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel);
  93. oRepository.Update(oDomain);
  94. }
  95. #endregion
  96.  
  97. #region Private
  98. private void InitAutoMapper<DtoModel, DomainModel>()
  99. {
  100. var oType = Mapper.FindTypeMapFor<DtoModel, DomainModel>();
  101. if (oType==null)
  102. {
  103. Mapper.CreateMap<DtoModel, DomainModel>();
  104. Mapper.CreateMap<DomainModel, DtoModel>();
  105. }
  106. }
  107. #endregion
  108. }

BaseService

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

2、UI层代码

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

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

2.1 ESTM.Web.IBLL代码

这个dll主要定义接口规则。

  1. public interface IPowerManager
  2. {
  3. List<DTO_TB_USERS> GetUsers(Expression<Func<DTO_TB_USERS, bool>> selector = null);
  4.  
  5. DTO_TB_USERS AddUser(DTO_TB_USERS oUser);
  6.  
  7. bool DeleteUser(DTO_TB_USERS oUser);
  8.  
  9. bool UpdateUser(DTO_TB_USERS oUser);
  10.  
  11. bool DeleteUser(Expression<Func<DTO_TB_USERS, bool>> selector = null);
  12.  
  13. List<DTO_TB_DEPARTMENT> GetDepartments(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null);
  14.  
  15. DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept);
  16.  
  17. bool DeleteDepartment(DTO_TB_DEPARTMENT oDept);
  18.  
  19. bool DeleteDepartment(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null);
  20.  
  21. bool UpdateDepartment(DTO_TB_DEPARTMENT oDept);
  22.  
  23. List<DTO_TB_ROLE> GetRoles(Expression<Func<DTO_TB_ROLE, bool>> selector = null);
  24.  
  25. List<DTO_TB_MENU> GetMenus(Expression<Func<DTO_TB_MENU, bool>> selector = null);
  26.  
  27. }

2.2 ESTM.Web.BLL代码

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

  1. [Export(typeof(IPowerManager))]
  2. public class PowerManager : IPowerManager
  3. {
  4. #region Fields
  5.      //创建WCF服务连接对象
  6. private ServiceReference_PowerManager.PowerManageWCFServiceClient oService = CreatePowerManagerService.GetInstance();
  7. #endregion
  8.  
  9. #region 接口实现
  10. public List<DTO_TB_USERS> GetUsers(Expression<Func<Common.DtoModel.DTO_TB_USERS, bool>> selector = null)
  11. {
  12. return oService.GetUsers(GetExpressionNode<DTO_TB_USERS>(selector));
  13. }
  14.  
  15. public List<Common.DtoModel.DTO_TB_DEPARTMENT> GetDepartments(Expression<Func<Common.DtoModel.DTO_TB_DEPARTMENT, bool>> selector = null)
  16. {
  17. return oService.GetDepartments(GetExpressionNode<DTO_TB_DEPARTMENT>(selector));
  18. }
  19.  
  20. public List<Common.DtoModel.DTO_TB_ROLE> GetRoles(Expression<Func<Common.DtoModel.DTO_TB_ROLE, bool>> selector = null)
  21. {
  22. return oService.GetRoles(GetExpressionNode<DTO_TB_ROLE>(selector));
  23. }
  24.  
  25. public List<Common.DtoModel.DTO_TB_MENU> GetMenus(Expression<Func<Common.DtoModel.DTO_TB_MENU, bool>> selector = null)
  26. {
  27. return oService.GetMenus(GetExpressionNode<DTO_TB_MENU>(selector));
  28. }
  29. #endregion
  30.  
  31. #region Privates
  32. //将lamada表达式转换为可用于WCF传递的ExpressionNode类型
  33. private ExpressionNode GetExpressionNode<Dto>(Expression<Func<Dto,bool>> selector)
  34. {
  35. if (selector == null)
  36. {
  37. return null;
  38. }
  39. ExpressionConverter expressionConverter = new ExpressionConverter();
  40. ExpressionNode expressionNode = expressionConverter.Convert(selector);
  41. return expressionNode;
  42. }
  43. #endregion
  44.  
  45. public DTO_TB_USERS AddUser(DTO_TB_USERS oUser)
  46. {
  47. return oService.AddUser(oUser);
  48. }
  49.  
  50. public bool DeleteUser(DTO_TB_USERS oUser)
  51. {
  52. return oService.DeleteUser(oUser);
  53. }
  54.  
  55. public bool DeleteUser(Expression<Func<DTO_TB_USERS, bool>> selector = null)
  56. {
  57. if (selector == null)
  58. {
  59. return false;
  60. }
  61. ExpressionConverter expressionConverter = new ExpressionConverter();
  62. ExpressionNode expressionNode = expressionConverter.Convert(selector);
  63. return oService.DeleteUserByLamada(expressionNode);
  64. }
  65.  
  66. public bool UpdateUser(DTO_TB_USERS oUser)
  67. {
  68. return oService.UpdateUser(oUser);
  69. }
  70.  
  71. public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept)
  72. {
  73. return oService.AddDepartment(oDept);
  74. }
  75.  
  76. public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept)
  77. {
  78. return oService.DeleteDepartment(oDept);
  79. }
  80.  
  81. public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept)
  82. {
  83. return oService.UpdateDepartment(oDept);
  84. }
  85.  
  86. public bool DeleteDepartment(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null)
  87. {
  88. if (selector == null)
  89. {
  90. return false;
  91. }
  92. ExpressionConverter expressionConverter = new ExpressionConverter();
  93. ExpressionNode expressionNode = expressionConverter.Convert(selector);
  94. return oService.DeleteDeptByLamada(expressionNode);
  95. }
  96. }

PowerManager : IPowerManager

  1.   public class CreatePowerManagerService
  2. {
  3. private static ServiceReference_PowerManager.PowerManageWCFServiceClient oPowerManagerClient = null;
  4. private static object obj = new object();
  5.  
  6. public static ServiceReference_PowerManager.PowerManageWCFServiceClient GetInstance()
  7. {
  8. lock (obj)
  9. {
  10. if (oPowerManagerClient == null)
  11. {
  12. oPowerManagerClient = new ServiceReference_PowerManager.PowerManageWCFServiceClient();
  13. }
  14. }
  15. return oPowerManagerClient;
  16. }
  17. }

由于是采用的添加服务引用的方式引用的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里面的对象。我们来看代码:

  1. public class PowerManagerController : BaseController
  2. {
  3. [Import]
  4. private IPowerManager PowerManager { set; get; }
  5.  
  6. #region Views
  7. // GET: PowerManager
  8. public ActionResult User()
  9. {
  10. return View();
  11. }
  12.  
  13. public ActionResult Role()
  14. {
  15. return View();
  16. }
  17.  
  18. public ActionResult Menu()
  19. {
  20. return View();
  21. }
  22.  
  23. public ActionResult Department()
  24. {
  25. return View();
  26. }
  27. #endregion
  28.  
  29. #region 部门管理
  30. public JsonResult GetDepartments(int limit, int offset, string departmentname, string statu)
  31. {
  32. //得到lamada表达式
  33. var oLamadaExtention = new LamadaExtention<DTO_TB_DEPARTMENT>();
  34. if (!string.IsNullOrEmpty(departmentname))
  35. {
  36. oLamadaExtention.GetExpression("DEPARTMENT_NAME", departmentname, ExpressionType.Contains);
  37. }
  38. if (!string.IsNullOrEmpty(statu))
  39. {
  40. oLamadaExtention.GetExpression("STATUS", statu, ExpressionType.Contains);
  41. }
  42. var lamada = oLamadaExtention.GetLambda();
  43. var lstRes = PowerManager.GetDepartments(lamada);
  44.  
  45. return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
  46. }
  47.  
  48. public object GetDepartmentEdit(string strPostData)
  49. {
  50. var oDepartment = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_DEPARTMENT>(strPostData);
  51. if (string.IsNullOrEmpty(oDepartment.DEPARTMENT_ID))
  52. {
  53. oDepartment.DEPARTMENT_ID = Guid.NewGuid().ToString();
  54. oDepartment = PowerManager.AddDepartment(oDepartment);
  55. }
  56. else
  57. {
  58. PowerManager.UpdateDepartment(oDepartment);
  59. }
  60. return oDepartment;
  61. }
  62.  
  63. public object DeleteDept(string strID)
  64. {
  65. PowerManager.DeleteDepartment(x=>x.DEPARTMENT_ID == strID);
  66. return new object();
  67. }
  68. #endregion
  69.  
  70. #region 菜单管理
  71. public JsonResult GetMenus(int limit, int offset, string menuname, string menuurl)
  72. {
  73. var oLamadaExtention = new LamadaExtention<DTO_TB_MENU>();
  74. if (!string.IsNullOrEmpty(menuname))
  75. {
  76. oLamadaExtention.GetExpression("MENU_NAME", menuname, ExpressionType.Contains);
  77. }
  78. if (!string.IsNullOrEmpty(menuurl))
  79. {
  80. oLamadaExtention.GetExpression("MENU_URL", menuurl, ExpressionType.Contains);
  81. }
  82. var lamada = oLamadaExtention.GetLambda();
  83. var lstRes = PowerManager.GetMenus(lamada).ToList();
  84.  
  85. return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
  86. }
  87.  
  88. public object GetMenuEdit(string strPostData)
  89. {
  90. var oMenu = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_MENU>(strPostData);
  91. if (string.IsNullOrEmpty(oMenu.MENU_ID))
  92. {
  93. //oMenu = MenuManager.Add(oMenu);
  94. }
  95. else
  96. {
  97. //MenuManager.Update(oMenu);
  98. }
  99. return oMenu;
  100. }
  101.  
  102. public object DeleteMenu(string strID)
  103. {
  104. //MenuManager.Delete(strID);
  105. return new object();
  106. }
  107.  
  108. public object GetParentMenu()
  109. {
  110. var lstMenu = PowerManager.GetMenus(x => x.MENU_LEVEL == "");
  111.  
  112. //var lstRes = RoleManager.Find().ToList();
  113. //var oRes = new PageRowData();
  114. //oRes.rows = lstRes.Skip(offset).Take(limit).ToList();
  115. //oRes.total = lstRes.Count;
  116. return lstMenu; ;
  117. }
  118.  
  119. public object GetChildrenMenu(string strParentID)
  120. {
  121. var lstMenu = PowerManager.GetMenus(x => x.MENU_LEVEL == "" && x.PARENT_ID == strParentID).ToList();
  122.  
  123. //var lstRes = RoleManager.Find().ToList();
  124. //var oRes = new PageRowData();
  125. //oRes.rows = lstRes.Skip(offset).Take(limit).ToList();
  126. //oRes.total = lstRes.Count;
  127. return lstMenu; ;
  128. }
  129. #endregion
  130.  
  131. #region 权限管理
  132.  
  133. public JsonResult GetRole(int limit, int offset, string rolename, string desc)
  134. {
  135. var oLamadaExtention = new LamadaExtention<DTO_TB_ROLE>();
  136. if (!string.IsNullOrEmpty(rolename))
  137. {
  138. oLamadaExtention.GetExpression("ROLE_NAME", rolename, ExpressionType.Contains);
  139. }
  140. if (!string.IsNullOrEmpty(desc))
  141. {
  142. oLamadaExtention.GetExpression("DESCRIPTION", desc, ExpressionType.Contains);
  143. }
  144. var lamada = oLamadaExtention.GetLambda();
  145. var lstRes = PowerManager.GetRoles(lamada).ToList();
  146.  
  147. return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
  148. }
  149.  
  150. #endregion
  151.  
  152. #region 用户管理
  153. public JsonResult GetUsers(int limit, int offset, string username, string fullname)
  154. {
  155. var oLamadaExtention = new LamadaExtention<DTO_TB_USERS>();
  156. if (!string.IsNullOrEmpty(username))
  157. {
  158. oLamadaExtention.GetExpression("USER_NAME", username, ExpressionType.Contains);
  159. }
  160. if (!string.IsNullOrEmpty(fullname))
  161. {
  162. oLamadaExtention.GetExpression("FULLNAME", fullname, ExpressionType.Contains);
  163. }
  164. var lamada = oLamadaExtention.GetLambda();
  165.  
  166. var lstRes = PowerManager.GetUsers(lamada).ToList();
  167.  
  168. return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
  169. }
  170.  
  171. public object GetUserEdit(string strPostData)
  172. {
  173. var oUser = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_USERS>(strPostData);
  174. if (string.IsNullOrEmpty(oUser.USER_ID))
  175. {
  176. oUser.USER_ID = Guid.NewGuid().ToString();
  177. oUser = PowerManager.AddUser(oUser);
  178. }
  179. else
  180. {
  181. PowerManager.UpdateUser(oUser);
  182. }
  183. return oUser;
  184. }
  185.  
  186. public object DeleteUser(string strID)
  187. {
  188. PowerManager.DeleteUser(x => x.USER_ID == strID);
  189. return new object();
  190. }
  191. #endregion
  192. }

PowerManagerController

View页面

  1. <!DOCTYPE html>
  2.  
  3. <html>
  4. <head>
  5. <meta name="viewport" content="width=device-width" />
  6. <title>@ViewBag.Title</title>
  7. @Styles.Render("~/Content/css")
  8. @Styles.Render("~/Content/table-css")
  9. @Scripts.Render("~/bundles/jquery")
  10. @Scripts.Render("~/bundles/bootstrap")
  11. @Scripts.Render("~/bundles/bootstrap-table")
  12. @RenderSection("Scripts", false)
  13. </head>
  14. <body>
  15. @RenderBody()
  16. </body>
  17. </html>

_Layout.cshtml

  1. @{
  2. ViewBag.Title = "部门管理";
  3. Layout = "~/Views/Shared/_Layout.cshtml";
  4. }
  5.  
  6. @Scripts.Render("~/bundles/PowerManage/DepartmentManage")
  7.  
  8. <div class="panel-body" style="padding-bottom:0px;">
  9. <div class="panel panel-default">
  10. <div class="panel-heading">查询条件</div>
  11. <div class="panel-body">
  12. <div class="row">
  13. <div class="col-md-4">
  14. <label for="txt_search_departmentname" class="col-sm-4 control-label" style="margin-top:6px;">部门名称</label>
  15. <span class="col-sm-8">
  16. <input type="text" class="form-control" id="txt_search_departmentname">
  17. </span>
  18. </div>
  19. <div class="col-md-4">
  20. <label for="txt_search_statu" class="col-sm-3 control-label" style="margin-top:6px;">状态</label>
  21. <span class="col-sm-8">
  22. <input type="text" class="form-control" id="txt_search_statu">
  23. </span>
  24. </div>
  25.  
  26. <div class="col-md-4">
  27. <button type="button" id="btn_query" class="btn btn-primary">查询</button>
  28. </div>
  29. </div>
  30.  
  31. </div>
  32. </div>
  33. </div>
  34.  
  35. <div id="toolbar" class="btn-group">
  36. <button id="btn_add" type="button" class="btn btn-default">
  37. <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
  38. </button>
  39. <button id="btn_edit" type="button" class="btn btn-default">
  40. <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>修改
  41. </button>
  42. <button id="btn_delete" type="button" class="btn btn-default">
  43. <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>删除
  44. </button>
  45. </div>
  46. <table id="tb_departments"></table>
  47.  
  48. <form>
  49. <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  50. <div class="modal-dialog" role="document">
  51. <div class="modal-content">
  52. <div class="modal-header">
  53. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  54. <h4 class="modal-title" id="myModalLabel">新增</h4>
  55. </div>
  56. <div class="modal-body">
  57.  
  58. <div class="form-group">
  59. <label for="txt_departmentname">部门名称</label>
  60. <input type="text" name="txt_departmentname" class="form-control" id="txt_departmentname" placeholder="部门名称">
  61. </div>
  62. <div class="form-group">
  63. <label for="txt_parentdepartment">上级部门</label>
  64. <input type="text" name="txt_parentdepartment" class="form-control" id="txt_parentdepartment" placeholder="上级部门">
  65. </div>
  66. <div class="form-group">
  67. <label for="txt_departmentlevel">部门级别</label>
  68. <input type="text" name="txt_departmentlevel" class="form-control" id="txt_departmentlevel" placeholder="部门级别">
  69. </div>
  70. <div class="form-group">
  71. <label for="txt_statu">状态</label>
  72. <input type="text" name="txt_statu" class="form-control" id="txt_statu" placeholder="状态">
  73. </div>
  74. </div>
  75. <div class="modal-footer">
  76. <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>关闭</button>
  77. <button type="button" id="btn_submit" class="btn btn-primary" data-dismiss="modal"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>保存</button>
  78. </div>
  79. </div>
  80. </div>
  81. </div>
  82. </form>

Department.cshtml

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

  1. $(function () {
  2. $('#tb_departments').bootstrapTable({
  3. url: '/PowerManager/GetDepartments',
  4. method: 'post',
  5. toolbar: '#toolbar',
  6. pagination: true,
  7. queryParams: queryParams,
  8. queryParamsType: "limit",
  9. //ajaxOptions: { departmentname: "", statu: "" },
  10. sidePagination: "server",
  11. pageSize: 5,
  12. pageList: [5, 25, 50, 100],
  13. search: true,
  14. strictSearch: true,
  15. showColumns: true,
  16. showRefresh: true,
  17. minimumCountColumns: 2,
  18. clickToSelect: true,
  19. columns: [{
  20. checkbox: true
  21. }, {
  22. field: 'DEPARTMENT_NAME',
  23. title: '部门名称'
  24. }, {
  25. field: 'PARENT_ID',
  26. title: '上级部门'
  27. }, {
  28. field: 'DEPARTMENT_LEVEL',
  29. title: '部门级别'
  30. }, {
  31. field: 'STATUS',
  32. title: '状态'
  33. }, ],
  34. onLoadSuccess: function (data) {
  35. var odata = data;
  36. }
  37. });
  38.  
  39. var oButtonInit = new ButtonInit();
  40. oButtonInit.Init();
  41.  
  42. });
  43.  
  44. function queryParams(params) { //配置参数
  45. var temp = { //这里的键的名字和控制器的变量名必须一直,这边改动,控制器也需要改成一样的
  46. limit: params.limit, //页面大小
  47. offset: params.offset, //页码
  48. departmentname: $("#txt_search_departmentname").val(),
  49. statu: $("#txt_search_statu").val()
  50. };
  51. return temp;
  52. }
  53.  
  54. var ButtonInit = function () {
  55. var oInit = new Object();
  56. var postdata = {};
  57.  
  58. oInit.Init = function () {
  59. $("#btn_add").click(function () {
  60. $("#myModalLabel").text("新增");
  61. $("#myModal").find(".form-control").val("");
  62. $('#myModal').modal()
  63.  
  64. postdata.DEPARTMENT_ID = "";
  65. });
  66.  
  67. $("#btn_edit").click(function () {
  68. var arrselections = $("#tb_departments").bootstrapTable('getSelections');
  69. if (arrselections.length > 1) {
  70. //alert("只能选择一行进行编辑");
  71. $("#btn_alert").alert();
  72. return;
  73. }
  74. if (arrselections.length <= 0) {
  75. //alert("请先选择需要编辑的行");
  76. $("#btn_alert").alert()
  77. return;
  78. }
  79. $("#myModalLabel").text("编辑");
  80. $("#txt_departmentname").val(arrselections[0].DEPARTMENT_NAME);
  81. $("#txt_parentdepartment").val(arrselections[0].PARENT_ID);
  82. $("#txt_departmentlevel").val(arrselections[0].DEPARTMENT_LEVEL);
  83. $("#txt_statu").val(arrselections[0].STATUS);
  84.  
  85. postdata.DEPARTMENT_ID = arrselections[0].DEPARTMENT_ID;
  86. $('#myModal').modal();
  87. });
  88.  
  89. $("#btn_delete").click(function () {
  90. var arrselections = $("#tb_departments").bootstrapTable('getSelections');
  91. if (arrselections.length <= 0) {
  92. //alert("请先选择需要编辑的行");
  93. $("#btn_alert").alert()
  94. return;
  95. }
  96.  
  97. if (!confirm("确定要删除选定的数据吗?")) {
  98. return;
  99. }
  100.  
  101. $.ajax({
  102. type: "post",
  103. url: "/PowerManager/DeleteDept",
  104. data: { strID: arrselections[0].DEPARTMENT_ID },
  105. success: function (data, status) {
  106. if (status == "success") {
  107. alert("提交数据成功");
  108. $("#tb_departments").bootstrapTable('refresh');
  109. }
  110. },
  111. error: function () {
  112. alert("error");
  113. },
  114. complete: function () {
  115. //alert("complete");
  116. }
  117.  
  118. });
  119. });
  120.  
  121. $("#btn_submit").click(function () {
  122. postdata.DEPARTMENT_NAME = $("#txt_departmentname").val();
  123. postdata.PARENT_ID = $("#txt_parentdepartment").val();
  124. postdata.DEPARTMENT_LEVEL = $("#txt_departmentlevel").val();
  125. postdata.STATUS = $("#txt_statu").val();
  126. $.ajax({
  127. type: "post",
  128. url: "/PowerManager/GetDepartmentEdit",
  129. data: { strPostData: JSON.stringify(postdata) },
  130. success: function (data, status) {
  131. if (status == "success") {
  132. alert("提交数据成功");
  133. $("#tb_departments").bootstrapTable('refresh');
  134. }
  135. },
  136. error: function () {
  137. //alert("error");
  138. },
  139. complete: function () {
  140. //alert("complete");
  141. }
  142.  
  143. });
  144. });
  145.  
  146. $("#btn_query").click(function () {
  147. $("#tb_departments").bootstrapTable('refresh');
  148. });
  149. };
  150.  
  151. return oInit;
  152. };

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

C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. DDD领域驱动设计初探(七):Web层的搭建

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

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

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

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

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

随机推荐

  1. javascript执行环境(执行期上下文)详解

    javascript执行环境(执行期上下文) 当js控制器(control)进入可执行代码时,控制器会进入一个执行环境,活动的多个执行环境构成执行环境栈,最上面的是正在运行的执行环境,当控制器进入一个 ...

  2. js中查找相同的几种函数

    function findInArr(arr,num){ for(var i=0;i<arr.length;i++){ if(arr[i]==num){ return true; } } ret ...

  3. 关于Ruby常用语法案例累积

    变量问题: 类变量和方法变量的区别是什么? 类变量:可以直接使用 方法变量:需要实例化后,才能使用该变量 案例一: class Person @@name = "Tom" @@na ...

  4. jQuery对表格的操作及其他应用

    表格操作 1.隔行变色:对普通表格进行隔行换色:单击显示高亮样式:复选框选中高亮 <!DOCTYPE html> <html> <head> <meta ht ...

  5. [Erlang 0106] Erlang实现Apple Push Notifications消息推送

        我们的IOS移动应用要实现消息推送,告诉用户有多少条消息未读,类似下图的效果(笑果),特把APNS和Erlang相关解决方案笔记于此备忘.          上面图片中是Apple Notif ...

  6. SqlServer--模糊查询-通配符

    查询所有姓张的同学Select * from student where left(sName,1)='张'   看上去很美,如果改成查询名字中带亮的学生怎么做?换一种做法 like  Select  ...

  7. winform窗体(一)——基本属性

    一.窗体设计界面 二.部分属性 1.基本 设计中的Name:窗体类的类名 AcceptButton:窗口的确定按钮Enter CancelButton:窗口按ESC的取消按钮 2.外观 Backcol ...

  8. JavaSe:Cookie 管理的API介绍

    CookieManager 在使用HttpURLConnection中,并没有关于Cookie的管理.如果使用Java程序时,怎么管理cookie呢? Cookie案例 1. User Agent - ...

  9. Loadrunner代理录制设置

    使用LR代理录制原理 启用LR代理服务器监听设置好的端口号是否有请求信息发送给服务器,有请求时,代理服务器接收带请求,并转发给对应的系统服务器,LR从而获取到请求的信息与数据,生成脚本. 使用代理的前 ...

  10. 谈谈Redis的SETNX

    谈谈Redis的SETNX 发表于2015-09-14 在 Redis 里,所谓 SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果,不 ...