C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建
前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码。之前的六篇完成了领域层、应用层、以及基础结构层的部分代码,这篇打算搭建下UI层的代码。
DDD领域驱动设计初探系列文章:
- C#进阶系列——DDD领域驱动设计初探(一):聚合
- C#进阶系列——DDD领域驱动设计初探(二):仓储Repository(上)
- C#进阶系列——DDD领域驱动设计初探(三):仓储Repository(下)
- C#进阶系列——DDD领域驱动设计初探(四):WCF搭建
- C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用
- C#进阶系列——DDD领域驱动设计初探(六):领域服务
- C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建
一、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/
二、代码示例
上篇完成了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接口实现代码:
- [ServiceClass]
- public class PowerManageWCFService :BaseService, IPowerManageWCFService
- {
- #region Fields
- [Import]
- private IUserRepository userRepository { get; set; }
- [Import]
- private IDepartmentRepository departmentRepository { get; set; }
- [Import]
- private IRoleRepository roleRepository { get; set; }
- [Import]
- private IMenuRepository menuRepository { get; set; }
- #endregion
- #region Constust
- public PowerManageWCFService()
- {
- }
- #endregion
- #region WCF服务接口实现
- #region 用户管理
- //这里参数为什么不直接用Expression<Func<DTO_TB_USERS,bool>>这种类型,是因为Expression不支持序列化,无法用于WCF数据的传递
- public List<DTO_TB_USERS> GetUsers(ExpressionNode expressionNode)
- {
- Expression<Func<DTO_TB_USERS, bool>> selector = null;
- if (expressionNode != null)
- {
- selector = expressionNode.ToExpression<Func<DTO_TB_USERS, bool>>();
- }
- var lstRes = base.GetDtoByLamada<DTO_TB_USERS, TB_USERS>(userRepository, selector);
- return lstRes;
- }
- public DTO_TB_USERS AddUser(DTO_TB_USERS oUser)
- {
- return base.AddDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser);
- }
- public bool DeleteUser(DTO_TB_USERS oUser)
- {
- var bRes = false;
- try
- {
- base.DeleteDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser);
- bRes = true;
- }
- catch
- {
- }
- return bRes;
- }
- public bool DeleteUserByLamada(ExpressionNode expressionNode)
- {
- Expression<Func<DTO_TB_USERS, bool>> selector = null;
- if (expressionNode != null)
- {
- selector = expressionNode.ToExpression<Func<DTO_TB_USERS, bool>>();
- }
- var bRes = false;
- try
- {
- base.DeleteDto<DTO_TB_USERS, TB_USERS>(userRepository, selector);
- bRes = true;
- }
- catch
- {
- }
- return bRes;
- }
- public bool UpdateUser(DTO_TB_USERS oUser)
- {
- var bRes = false;
- try
- {
- base.UpdateDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser);
- bRes = true;
- }
- catch
- {
- }
- return bRes;
- }
- #endregion
- #region 部门管理
- public List<DTO_TB_DEPARTMENT> GetDepartments(ExpressionNode expressionNode)
- {
- Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null;
- if (expressionNode != null)
- {
- selector = expressionNode.ToExpression<Func<DTO_TB_DEPARTMENT, bool>>();
- }
- return base.GetDtoByLamada<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, selector);
- }
- public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept)
- {
- return base.AddDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept);
- }
- public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept)
- {
- var bRes = false;
- try
- {
- base.DeleteDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept);
- bRes = true;
- }
- catch
- {
- }
- return bRes;
- }
- public bool DeleteDeptByLamada(ExpressionNode expressionNode)
- {
- Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null;
- if (expressionNode != null)
- {
- selector = expressionNode.ToExpression<Func<DTO_TB_DEPARTMENT, bool>>();
- }
- var bRes = false;
- try
- {
- base.DeleteDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, selector);
- bRes = true;
- }
- catch
- {
- }
- return bRes;
- }
- public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept)
- {
- var bRes = false;
- try
- {
- base.UpdateDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept);
- bRes = true;
- }
- catch
- {
- }
- return bRes;
- }
- #endregion
- #region 角色管理
- public List<DTO_TB_ROLE> GetRoles(ExpressionNode expressionNode)
- {
- Expression<Func<DTO_TB_ROLE, bool>> selector = null;
- if (expressionNode != null)
- {
- selector = expressionNode.ToExpression<Func<DTO_TB_ROLE, bool>>();
- }
- return base.GetDtoByLamada<DTO_TB_ROLE, TB_ROLE>(roleRepository, selector);
- }
- public DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole)
- {
- return base.AddDto<DTO_TB_ROLE, TB_ROLE>(roleRepository, oRole);
- }
- #endregion
- #region 菜单管理
- public List<DTO_TB_MENU> GetMenus(ExpressionNode expressionNode)
- {
- Expression<Func<DTO_TB_MENU, bool>> selector = null;
- if (expressionNode != null)
- {
- selector = expressionNode.ToExpression<Func<DTO_TB_MENU, bool>>();
- }
- return base.GetDtoByLamada<DTO_TB_MENU, TB_MENU>(menuRepository, selector);
- }
- public DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu)
- {
- return base.AddDto<DTO_TB_MENU, TB_MENU>(menuRepository, oMenu);
- }
- #endregion
- #endregion
- }
PowerManageWCFService
这里要说明一点,在通过lamada表达式查询的方法里面为什么不直接用Expression<Func<DTO_TB_USERS,bool>>这种类型,而要使用ExpressionNode这种类型的变量呢?
这是因为Expression不支持序列化,无法用于WCF数据的传递。ExpressionNode这个对象的使用需要添加Serialize.Linq这个dll的引用,还好有我们神奇的NuGet,让我们再也不用去网上找一大堆的dll了。
我们公用的增删改查封装到了BaseService这个父类里面。
1.3 BaseService代码
- public class BaseService
- {
- #region Fields
- private bool bInitAutoMapper = false;
- #endregion
- #region Construct
- public BaseService()
- {
- //注册MEF
- Regisgter.regisgter().ComposeParts(this);
- }
- #endregion
- #region 查询
- /// <summary>
- /// 通用单表查询方法
- /// </summary>
- /// <typeparam name="DtoModel">DTOmodel</typeparam>
- /// <typeparam name="DomainModel">领域模型</typeparam>
- /// <param name="oRepository">需要传过来的仓储接口对象</param>
- /// <param name="selector">前端传过来的lamada表达式</param>
- /// <returns></returns>
- public List<DtoModel> GetDtoByLamada<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, Expression<Func<DtoModel, bool>> selector = null)
- where DomainModel : AggregateRoot
- where DtoModel : Dto_BaseModel
- {
- InitAutoMapper<DtoModel, DomainModel>();
- if (selector == null)
- {
- var lstDomainModel = oRepository.Entities.ToList();
- return Mapper.Map<List<DomainModel>, List<DtoModel>>(lstDomainModel);
- }
- //得到从Web传过来和DTOModel相关的lamaba表达式的委托
- Func<DtoModel, bool> match = selector.Compile();
- //创建映射Expression的委托
- Func<DomainModel, DtoModel> mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression<DomainModel, DtoModel>(Mapper.Engine).Compile();
- //得到领域Model相关的lamada
- Expression<Func<DomainModel, bool>> lamada = ef_t => match(mapper(ef_t));
- List<DomainModel> list = oRepository.Find(lamada).ToList();
- return Mapper.Map<List<DomainModel>, List<DtoModel>>(list);
- }
- #endregion
- #region 新增
- public DtoModel AddDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel)
- where DomainModel : AggregateRoot
- where DtoModel : Dto_BaseModel
- {
- InitAutoMapper<DtoModel, DomainModel>();
- var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel);
- oRepository.Insert(oDomain);
- return Mapper.Map<DomainModel, DtoModel>(oDomain);
- }
- #endregion
- #region 删除
- public int DeleteDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel)
- where DomainModel : AggregateRoot
- where DtoModel : Dto_BaseModel
- {
- InitAutoMapper<DtoModel, DomainModel>();
- var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel);
- return oRepository.Delete(oDomain);
- }
- public int DeleteDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, Expression<Func<DtoModel, bool>> selector = null)
- where DomainModel : AggregateRoot
- where DtoModel : Dto_BaseModel
- {
- InitAutoMapper<DtoModel, DomainModel>();
- if (selector == null)
- {
- return ;
- }
- //得到从Web传过来和DTOModel相关的lamaba表达式的委托
- Func<DtoModel, bool> match = selector.Compile();
- //创建映射Expression的委托
- Func<DomainModel, DtoModel> mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression<DomainModel, DtoModel>(Mapper.Engine).Compile();
- //得到领域Model相关的lamada
- Expression<Func<DomainModel, bool>> lamada = ef_t => match(mapper(ef_t));
- return oRepository.Delete(lamada);
- }
- #endregion
- #region 更新
- public void UpdateDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel)
- where DomainModel : AggregateRoot
- where DtoModel : Dto_BaseModel
- {
- InitAutoMapper<DtoModel, DomainModel>();
- var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel);
- oRepository.Update(oDomain);
- }
- #endregion
- #region Private
- private void InitAutoMapper<DtoModel, DomainModel>()
- {
- var oType = Mapper.FindTypeMapFor<DtoModel, DomainModel>();
- if (oType==null)
- {
- Mapper.CreateMap<DtoModel, DomainModel>();
- Mapper.CreateMap<DomainModel, DtoModel>();
- }
- }
- #endregion
- }
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里面的接口方法
- [Export(typeof(IPowerManager))]
- public class PowerManager : IPowerManager
- {
- #region Fields
- //创建WCF服务连接对象
- private ServiceReference_PowerManager.PowerManageWCFServiceClient oService = CreatePowerManagerService.GetInstance();
- #endregion
- #region 接口实现
- public List<DTO_TB_USERS> GetUsers(Expression<Func<Common.DtoModel.DTO_TB_USERS, bool>> selector = null)
- {
- return oService.GetUsers(GetExpressionNode<DTO_TB_USERS>(selector));
- }
- public List<Common.DtoModel.DTO_TB_DEPARTMENT> GetDepartments(Expression<Func<Common.DtoModel.DTO_TB_DEPARTMENT, bool>> selector = null)
- {
- return oService.GetDepartments(GetExpressionNode<DTO_TB_DEPARTMENT>(selector));
- }
- public List<Common.DtoModel.DTO_TB_ROLE> GetRoles(Expression<Func<Common.DtoModel.DTO_TB_ROLE, bool>> selector = null)
- {
- return oService.GetRoles(GetExpressionNode<DTO_TB_ROLE>(selector));
- }
- public List<Common.DtoModel.DTO_TB_MENU> GetMenus(Expression<Func<Common.DtoModel.DTO_TB_MENU, bool>> selector = null)
- {
- return oService.GetMenus(GetExpressionNode<DTO_TB_MENU>(selector));
- }
- #endregion
- #region Privates
- //将lamada表达式转换为可用于WCF传递的ExpressionNode类型
- private ExpressionNode GetExpressionNode<Dto>(Expression<Func<Dto,bool>> selector)
- {
- if (selector == null)
- {
- return null;
- }
- ExpressionConverter expressionConverter = new ExpressionConverter();
- ExpressionNode expressionNode = expressionConverter.Convert(selector);
- return expressionNode;
- }
- #endregion
- public DTO_TB_USERS AddUser(DTO_TB_USERS oUser)
- {
- return oService.AddUser(oUser);
- }
- public bool DeleteUser(DTO_TB_USERS oUser)
- {
- return oService.DeleteUser(oUser);
- }
- public bool DeleteUser(Expression<Func<DTO_TB_USERS, bool>> selector = null)
- {
- if (selector == null)
- {
- return false;
- }
- ExpressionConverter expressionConverter = new ExpressionConverter();
- ExpressionNode expressionNode = expressionConverter.Convert(selector);
- return oService.DeleteUserByLamada(expressionNode);
- }
- public bool UpdateUser(DTO_TB_USERS oUser)
- {
- return oService.UpdateUser(oUser);
- }
- public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept)
- {
- return oService.AddDepartment(oDept);
- }
- public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept)
- {
- return oService.DeleteDepartment(oDept);
- }
- public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept)
- {
- return oService.UpdateDepartment(oDept);
- }
- public bool DeleteDepartment(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null)
- {
- if (selector == null)
- {
- return false;
- }
- ExpressionConverter expressionConverter = new ExpressionConverter();
- ExpressionNode expressionNode = expressionConverter.Convert(selector);
- return oService.DeleteDeptByLamada(expressionNode);
- }
- }
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里面的对象。我们来看代码:
- public class PowerManagerController : BaseController
- {
- [Import]
- private IPowerManager PowerManager { set; get; }
- #region Views
- // GET: PowerManager
- public ActionResult User()
- {
- return View();
- }
- public ActionResult Role()
- {
- return View();
- }
- public ActionResult Menu()
- {
- return View();
- }
- public ActionResult Department()
- {
- return View();
- }
- #endregion
- #region 部门管理
- public JsonResult GetDepartments(int limit, int offset, string departmentname, string statu)
- {
- //得到lamada表达式
- var oLamadaExtention = new LamadaExtention<DTO_TB_DEPARTMENT>();
- if (!string.IsNullOrEmpty(departmentname))
- {
- oLamadaExtention.GetExpression("DEPARTMENT_NAME", departmentname, ExpressionType.Contains);
- }
- if (!string.IsNullOrEmpty(statu))
- {
- oLamadaExtention.GetExpression("STATUS", statu, ExpressionType.Contains);
- }
- var lamada = oLamadaExtention.GetLambda();
- var lstRes = PowerManager.GetDepartments(lamada);
- return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
- }
- public object GetDepartmentEdit(string strPostData)
- {
- var oDepartment = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_DEPARTMENT>(strPostData);
- if (string.IsNullOrEmpty(oDepartment.DEPARTMENT_ID))
- {
- oDepartment.DEPARTMENT_ID = Guid.NewGuid().ToString();
- oDepartment = PowerManager.AddDepartment(oDepartment);
- }
- else
- {
- PowerManager.UpdateDepartment(oDepartment);
- }
- return oDepartment;
- }
- public object DeleteDept(string strID)
- {
- PowerManager.DeleteDepartment(x=>x.DEPARTMENT_ID == strID);
- return new object();
- }
- #endregion
- #region 菜单管理
- public JsonResult GetMenus(int limit, int offset, string menuname, string menuurl)
- {
- var oLamadaExtention = new LamadaExtention<DTO_TB_MENU>();
- if (!string.IsNullOrEmpty(menuname))
- {
- oLamadaExtention.GetExpression("MENU_NAME", menuname, ExpressionType.Contains);
- }
- if (!string.IsNullOrEmpty(menuurl))
- {
- oLamadaExtention.GetExpression("MENU_URL", menuurl, ExpressionType.Contains);
- }
- var lamada = oLamadaExtention.GetLambda();
- var lstRes = PowerManager.GetMenus(lamada).ToList();
- return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
- }
- public object GetMenuEdit(string strPostData)
- {
- var oMenu = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_MENU>(strPostData);
- if (string.IsNullOrEmpty(oMenu.MENU_ID))
- {
- //oMenu = MenuManager.Add(oMenu);
- }
- else
- {
- //MenuManager.Update(oMenu);
- }
- return oMenu;
- }
- public object DeleteMenu(string strID)
- {
- //MenuManager.Delete(strID);
- return new object();
- }
- public object GetParentMenu()
- {
- var lstMenu = PowerManager.GetMenus(x => x.MENU_LEVEL == "");
- //var lstRes = RoleManager.Find().ToList();
- //var oRes = new PageRowData();
- //oRes.rows = lstRes.Skip(offset).Take(limit).ToList();
- //oRes.total = lstRes.Count;
- return lstMenu; ;
- }
- public object GetChildrenMenu(string strParentID)
- {
- var lstMenu = PowerManager.GetMenus(x => x.MENU_LEVEL == "" && x.PARENT_ID == strParentID).ToList();
- //var lstRes = RoleManager.Find().ToList();
- //var oRes = new PageRowData();
- //oRes.rows = lstRes.Skip(offset).Take(limit).ToList();
- //oRes.total = lstRes.Count;
- return lstMenu; ;
- }
- #endregion
- #region 权限管理
- public JsonResult GetRole(int limit, int offset, string rolename, string desc)
- {
- var oLamadaExtention = new LamadaExtention<DTO_TB_ROLE>();
- if (!string.IsNullOrEmpty(rolename))
- {
- oLamadaExtention.GetExpression("ROLE_NAME", rolename, ExpressionType.Contains);
- }
- if (!string.IsNullOrEmpty(desc))
- {
- oLamadaExtention.GetExpression("DESCRIPTION", desc, ExpressionType.Contains);
- }
- var lamada = oLamadaExtention.GetLambda();
- var lstRes = PowerManager.GetRoles(lamada).ToList();
- return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
- }
- #endregion
- #region 用户管理
- public JsonResult GetUsers(int limit, int offset, string username, string fullname)
- {
- var oLamadaExtention = new LamadaExtention<DTO_TB_USERS>();
- if (!string.IsNullOrEmpty(username))
- {
- oLamadaExtention.GetExpression("USER_NAME", username, ExpressionType.Contains);
- }
- if (!string.IsNullOrEmpty(fullname))
- {
- oLamadaExtention.GetExpression("FULLNAME", fullname, ExpressionType.Contains);
- }
- var lamada = oLamadaExtention.GetLambda();
- var lstRes = PowerManager.GetUsers(lamada).ToList();
- return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet);
- }
- public object GetUserEdit(string strPostData)
- {
- var oUser = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_USERS>(strPostData);
- if (string.IsNullOrEmpty(oUser.USER_ID))
- {
- oUser.USER_ID = Guid.NewGuid().ToString();
- oUser = PowerManager.AddUser(oUser);
- }
- else
- {
- PowerManager.UpdateUser(oUser);
- }
- return oUser;
- }
- public object DeleteUser(string strID)
- {
- PowerManager.DeleteUser(x => x.USER_ID == strID);
- return new object();
- }
- #endregion
- }
PowerManagerController
View页面
- <!DOCTYPE html>
- <html>
- <head>
- <meta name="viewport" content="width=device-width" />
- <title>@ViewBag.Title</title>
- @Styles.Render("~/Content/css")
- @Styles.Render("~/Content/table-css")
- @Scripts.Render("~/bundles/jquery")
- @Scripts.Render("~/bundles/bootstrap")
- @Scripts.Render("~/bundles/bootstrap-table")
- @RenderSection("Scripts", false)
- </head>
- <body>
- @RenderBody()
- </body>
- </html>
_Layout.cshtml
- @{
- ViewBag.Title = "部门管理";
- Layout = "~/Views/Shared/_Layout.cshtml";
- }
- @Scripts.Render("~/bundles/PowerManage/DepartmentManage")
- <div class="panel-body" style="padding-bottom:0px;">
- <div class="panel panel-default">
- <div class="panel-heading">查询条件</div>
- <div class="panel-body">
- <div class="row">
- <div class="col-md-4">
- <label for="txt_search_departmentname" class="col-sm-4 control-label" style="margin-top:6px;">部门名称</label>
- <span class="col-sm-8">
- <input type="text" class="form-control" id="txt_search_departmentname">
- </span>
- </div>
- <div class="col-md-4">
- <label for="txt_search_statu" class="col-sm-3 control-label" style="margin-top:6px;">状态</label>
- <span class="col-sm-8">
- <input type="text" class="form-control" id="txt_search_statu">
- </span>
- </div>
- <div class="col-md-4">
- <button type="button" id="btn_query" class="btn btn-primary">查询</button>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div id="toolbar" class="btn-group">
- <button id="btn_add" type="button" class="btn btn-default">
- <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增
- </button>
- <button id="btn_edit" type="button" class="btn btn-default">
- <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>修改
- </button>
- <button id="btn_delete" type="button" class="btn btn-default">
- <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>删除
- </button>
- </div>
- <table id="tb_departments"></table>
- <form>
- <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
- <div class="modal-dialog" role="document">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
- <h4 class="modal-title" id="myModalLabel">新增</h4>
- </div>
- <div class="modal-body">
- <div class="form-group">
- <label for="txt_departmentname">部门名称</label>
- <input type="text" name="txt_departmentname" class="form-control" id="txt_departmentname" placeholder="部门名称">
- </div>
- <div class="form-group">
- <label for="txt_parentdepartment">上级部门</label>
- <input type="text" name="txt_parentdepartment" class="form-control" id="txt_parentdepartment" placeholder="上级部门">
- </div>
- <div class="form-group">
- <label for="txt_departmentlevel">部门级别</label>
- <input type="text" name="txt_departmentlevel" class="form-control" id="txt_departmentlevel" placeholder="部门级别">
- </div>
- <div class="form-group">
- <label for="txt_statu">状态</label>
- <input type="text" name="txt_statu" class="form-control" id="txt_statu" placeholder="状态">
- </div>
- </div>
- <div class="modal-footer">
- <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>关闭</button>
- <button type="button" id="btn_submit" class="btn btn-primary" data-dismiss="modal"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>保存</button>
- </div>
- </div>
- </div>
- </div>
- </form>
Department.cshtml
JS代码我们来看一个页面就好了,其他页面类似:
- $(function () {
- $('#tb_departments').bootstrapTable({
- url: '/PowerManager/GetDepartments',
- method: 'post',
- toolbar: '#toolbar',
- pagination: true,
- queryParams: queryParams,
- queryParamsType: "limit",
- //ajaxOptions: { departmentname: "", statu: "" },
- sidePagination: "server",
- pageSize: 5,
- pageList: [5, 25, 50, 100],
- search: true,
- strictSearch: true,
- showColumns: true,
- showRefresh: true,
- minimumCountColumns: 2,
- clickToSelect: true,
- columns: [{
- checkbox: true
- }, {
- field: 'DEPARTMENT_NAME',
- title: '部门名称'
- }, {
- field: 'PARENT_ID',
- title: '上级部门'
- }, {
- field: 'DEPARTMENT_LEVEL',
- title: '部门级别'
- }, {
- field: 'STATUS',
- title: '状态'
- }, ],
- onLoadSuccess: function (data) {
- var odata = data;
- }
- });
- var oButtonInit = new ButtonInit();
- oButtonInit.Init();
- });
- function queryParams(params) { //配置参数
- var temp = { //这里的键的名字和控制器的变量名必须一直,这边改动,控制器也需要改成一样的
- limit: params.limit, //页面大小
- offset: params.offset, //页码
- departmentname: $("#txt_search_departmentname").val(),
- statu: $("#txt_search_statu").val()
- };
- return temp;
- }
- var ButtonInit = function () {
- var oInit = new Object();
- var postdata = {};
- oInit.Init = function () {
- $("#btn_add").click(function () {
- $("#myModalLabel").text("新增");
- $("#myModal").find(".form-control").val("");
- $('#myModal').modal()
- postdata.DEPARTMENT_ID = "";
- });
- $("#btn_edit").click(function () {
- var arrselections = $("#tb_departments").bootstrapTable('getSelections');
- if (arrselections.length > 1) {
- //alert("只能选择一行进行编辑");
- $("#btn_alert").alert();
- return;
- }
- if (arrselections.length <= 0) {
- //alert("请先选择需要编辑的行");
- $("#btn_alert").alert()
- return;
- }
- $("#myModalLabel").text("编辑");
- $("#txt_departmentname").val(arrselections[0].DEPARTMENT_NAME);
- $("#txt_parentdepartment").val(arrselections[0].PARENT_ID);
- $("#txt_departmentlevel").val(arrselections[0].DEPARTMENT_LEVEL);
- $("#txt_statu").val(arrselections[0].STATUS);
- postdata.DEPARTMENT_ID = arrselections[0].DEPARTMENT_ID;
- $('#myModal').modal();
- });
- $("#btn_delete").click(function () {
- var arrselections = $("#tb_departments").bootstrapTable('getSelections');
- if (arrselections.length <= 0) {
- //alert("请先选择需要编辑的行");
- $("#btn_alert").alert()
- return;
- }
- if (!confirm("确定要删除选定的数据吗?")) {
- return;
- }
- $.ajax({
- type: "post",
- url: "/PowerManager/DeleteDept",
- data: { strID: arrselections[0].DEPARTMENT_ID },
- success: function (data, status) {
- if (status == "success") {
- alert("提交数据成功");
- $("#tb_departments").bootstrapTable('refresh');
- }
- },
- error: function () {
- alert("error");
- },
- complete: function () {
- //alert("complete");
- }
- });
- });
- $("#btn_submit").click(function () {
- postdata.DEPARTMENT_NAME = $("#txt_departmentname").val();
- postdata.PARENT_ID = $("#txt_parentdepartment").val();
- postdata.DEPARTMENT_LEVEL = $("#txt_departmentlevel").val();
- postdata.STATUS = $("#txt_statu").val();
- $.ajax({
- type: "post",
- url: "/PowerManager/GetDepartmentEdit",
- data: { strPostData: JSON.stringify(postdata) },
- success: function (data, status) {
- if (status == "success") {
- alert("提交数据成功");
- $("#tb_departments").bootstrapTable('refresh');
- }
- },
- error: function () {
- //alert("error");
- },
- complete: function () {
- //alert("complete");
- }
- });
- });
- $("#btn_query").click(function () {
- $("#tb_departments").bootstrapTable('refresh');
- });
- };
- return oInit;
- };
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层的搭建的更多相关文章
- C#进阶系列——DDD领域驱动设计初探(一):聚合
前言:又有差不多半个月没写点什么了,感觉这样很对不起自己似的.今天看到一篇博文里面写道:越是忙人越有时间写博客.呵呵,似乎有点道理,博主为了证明自己也是忙人,这不就来学习下DDD这么一个听上去高大上的 ...
- C#进阶系列——DDD领域驱动设计初探(二):仓储Repository(上)
前言:上篇介绍了DDD设计Demo里面的聚合划分以及实体和聚合根的设计,这章继续来说说DDD里面最具争议的话题之一的仓储Repository,为什么Repository会有这么大的争议,博主认为主要原 ...
- C#进阶系列——DDD领域驱动设计初探(三):仓储Repository(下)
前言:上篇介绍了下仓储的代码架构示例以及简单分析了仓储了使用优势.本章还是继续来完善下仓储的设计.上章说了,仓储的最主要作用的分离领域层和具体的技术架构,使得领域层更加专注领域逻辑.那么涉及到具体的实 ...
- C#进阶系列——DDD领域驱动设计初探(四):WCF搭建
前言:前面三篇分享了下DDD里面的两个主要特性:聚合和仓储.领域层的搭建基本完成,当然还涉及到领域事件和领域服务的部分,后面再项目搭建的过程中慢慢引入,博主的思路是先将整个架构走通,然后一步一步来添加 ...
- C#进阶系列——DDD领域驱动设计初探(五):AutoMapper使用
前言:前篇搭建了下WCF的代码,就提到了DTO的概念,对于为什么要有这么一个DTO的对象,上章可能对于这点不太详尽,在此不厌其烦再来提提它的作用: 从安全上面考虑,领域Model都带有领域业务,让Cl ...
- C#进阶系列——DDD领域驱动设计初探(六):领域服务
前言:之前一直在搭建项目架构的代码,有点偏离我们的主题(DDD)了,这篇我们继续来聊聊DDD里面另一个比较重要的知识点:领域服务.关于领域服务的使用,书中也介绍得比较晦涩,在此就根据博主自己的理解谈谈 ...
- DDD领域驱动设计初探(七):Web层的搭建
前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码.之前的六篇完成了领域层.应用层.以及基础结构层的部分代码,这篇打算搭建下UI层的代码. DDD领域驱动设计初 ...
- DDD领域驱动设计初探(六):领域服务
前言:之前一直在搭建项目架构的代码,有点偏离我们的主题(DDD)了,这篇我们继续来聊聊DDD里面另一个比较重要的知识点:领域服务.关于领域服务的使用,书中也介绍得比较晦涩,在此就根据博主自己的理解谈谈 ...
- DDD领域驱动设计初探(五):AutoMapper使用
前言:前篇搭建了下WCF的代码,就提到了DTO的概念,对于为什么要有这么一个DTO的对象,上章可能对于这点不太详尽,在此不厌其烦再来提提它的作用: 从安全上面考虑,领域Model都带有领域业务,让Cl ...
随机推荐
- javascript执行环境(执行期上下文)详解
javascript执行环境(执行期上下文) 当js控制器(control)进入可执行代码时,控制器会进入一个执行环境,活动的多个执行环境构成执行环境栈,最上面的是正在运行的执行环境,当控制器进入一个 ...
- js中查找相同的几种函数
function findInArr(arr,num){ for(var i=0;i<arr.length;i++){ if(arr[i]==num){ return true; } } ret ...
- 关于Ruby常用语法案例累积
变量问题: 类变量和方法变量的区别是什么? 类变量:可以直接使用 方法变量:需要实例化后,才能使用该变量 案例一: class Person @@name = "Tom" @@na ...
- jQuery对表格的操作及其他应用
表格操作 1.隔行变色:对普通表格进行隔行换色:单击显示高亮样式:复选框选中高亮 <!DOCTYPE html> <html> <head> <meta ht ...
- [Erlang 0106] Erlang实现Apple Push Notifications消息推送
我们的IOS移动应用要实现消息推送,告诉用户有多少条消息未读,类似下图的效果(笑果),特把APNS和Erlang相关解决方案笔记于此备忘. 上面图片中是Apple Notif ...
- SqlServer--模糊查询-通配符
查询所有姓张的同学Select * from student where left(sName,1)='张' 看上去很美,如果改成查询名字中带亮的学生怎么做?换一种做法 like Select ...
- winform窗体(一)——基本属性
一.窗体设计界面 二.部分属性 1.基本 设计中的Name:窗体类的类名 AcceptButton:窗口的确定按钮Enter CancelButton:窗口按ESC的取消按钮 2.外观 Backcol ...
- JavaSe:Cookie 管理的API介绍
CookieManager 在使用HttpURLConnection中,并没有关于Cookie的管理.如果使用Java程序时,怎么管理cookie呢? Cookie案例 1. User Agent - ...
- Loadrunner代理录制设置
使用LR代理录制原理 启用LR代理服务器监听设置好的端口号是否有请求信息发送给服务器,有请求时,代理服务器接收带请求,并转发给对应的系统服务器,LR从而获取到请求的信息与数据,生成脚本. 使用代理的前 ...
- 谈谈Redis的SETNX
谈谈Redis的SETNX 发表于2015-09-14 在 Redis 里,所谓 SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果,不 ...