ABP展现层实现增删改查
这一章节将通过完善Controller、View、ViewModel,来实现展现层的增删改查。最终实现效果如下图:展现层最终效果一、定义ControllerABP对ASP.NETMVCControllers进行了集成,通过引入Abp.Web.Mvc命名空间,创建Controller继承自AbpController,我们即可使用ABP附加给我们的以下强大功能:本地化异常处理对返回的JsonResult进行包装审计日志权限认证([AbpMvcAuthorize]特性)工作单元(默认未开启,通过添加[UnitOfWork]开启)1,创建TasksController继承自AbpController通过构造函数注入对应用服务的依赖。[AbpMvcAuthorize]public>TasksController:AbpController{privatereadonlyITaskAppService_taskAppService;privatereadonlyIUserAppService_userAppService;publicTasksController(ITaskAppServicetaskAppService,IUserAppServiceuserAppService){_taskAppService=taskAppService;_userAppService=userAppService;}}二、创建列表展示分部视图(_List.cshtml)在分部视图中,我们通过循环遍历,输出任务清单。@modelIEnumerable<LearningMpaAbp.Tasks.Dtos.TaskDto><div><ul>="list-group">@foreach(vartaskinModel){<li>="list-group-item"><div>="btn-grouppull-right"><buttontype="button">="btnbtn-info"onclick="editTask(@task.Id);">Edit</button><buttontype="button">="btnbtn-success"onclick="deleteTask(@task.Id);">Delete</button></div><div>="media"><a>="media-left">"#"><i>="fa@task.GetTaskLable()fa-3x"></i></a><div>="media-body"><h4>="media-heading">@task.Title</h4><p>="text-info">@task.AssignedPersonName</p><span>="text-muted">@task.CreationTime.ToString("yyyy-MM-ddHH:mm:ss")</span></div></div></li>}</ul></div>列表显示效果三,创建新增分部视图(_CreateTask.cshtml)为了好的用户体验,我们采用异步加载的方式来实现任务的创建。1,引入js文件使用异步提交需要引入jquery.validate.unobtrusive.min.js和jquery.unobtrusive-ajax.min.js,其中jquery.unobtrusive-ajax.min.js,需要通过Nuget安装微软的Microsoft.jQuery.Unobtrusive.Ajax包获取。然后通过捆绑一同引入到视图中。打开App_Start文件夹下的BundleConfig.cs,添加以下代码:bundles.Add(newScriptBundle("~/Bundles/unobtrusive/js").Include("~/Scripts/jquery.validate.unobtrusive.min.js","~/Scripts/jquery.unobtrusive-ajax.min.js"));找到Views/Shared/_Layout.cshtml,添加对捆绑的js引用。@Scripts.Render("~/Bundles/vendor/js/bottom")@Scripts.Render("~/Bundles/js")//在此处添加下面一行代码@Scripts.Render("~/Bundles/unobtrusive/js")2,创建分部视图其中用到了Bootstrap-Modal,Ajax.BeginForm,对此不了解的可以参考Ajax.BeginForm()知多少Bootstrap-Modal的用法介绍该PartialView绑定CreateTaskInput模型。最终_CreateTask.cshtml代码如下:@modelLearningMpaAbp.Tasks.Dtos.CreateTaskInput@{ViewBag.Title="Create";}<div>="modalfade"id="add"tabindex="-1"role="dialog"aria-labelledby="createTask"data-backdrop="static"><div>="modal-dialog"role="document"><div>="modal-content"><div>="modal-header"><buttontype="button">="close"data-dismiss="modal"><spanaria-hidden="true">×</span><span>="sr-only">Close</span></button><h4>="modal-title"id="myModalLabel">CreateTask</h4></div><div>="modal-body"id="modalContent">@using(Ajax.BeginForm("Create","Tasks",newAjaxOptions(){UpdateTargetId="taskList",InsertionMode=InsertionMode.Replace,OnBegin="beginPost('#add')",OnSuccess="hideForm('#add')",OnFailure="errorPost(xhr,status,error,'#add')"})){@Html.AntiForgeryToken()<div>="form-horizontal"><h4>Task</h4><hr/>@Html.ValidationSummary(true,"",new{@>="text-danger"})<div>="form-group">@Html.LabelFor(model=>model.AssignedPersonId,"AssignedPersonId",htmlAttributes:new{@>="control-labelcol-md-2"})<div>="col-md-10">@Html.DropDownList("AssignedPersonId",null,htmlAttributes:new{@>="form-control"})@Html.ValidationMessageFor(model=>model.AssignedPersonId,"",new{@>="text-danger"})</div></div><div>="form-group">@Html.LabelFor(model=>model.Title,htmlAttributes:new{@>="control-labelcol-md-2"})<div>="col-md-10">@Html.EditorFor(model=>model.Title,new{htmlAttributes=new{@>="form-control"}})@Html.ValidationMessageFor(model=>model.Title,"",new{@>="text-danger"})</div></div><div>="form-group">@Html.LabelFor(model=>model.Description,htmlAttributes:new{@>="control-labelcol-md-2"})<div>="col-md-10">@Html.EditorFor(model=>model.Description,new{htmlAttributes=new{@>="form-control"}})@Html.ValidationMessageFor(model=>model.Description,"",new{@>="text-danger"})</div></div><div>="form-group">@Html.LabelFor(model=>model.State,htmlAttributes:new{@>="control-labelcol-md-2"})<div>="col-md-10">@Html.EnumDropDownListFor(model=>model.State,htmlAttributes:new{@>="form-control"})@Html.ValidationMessageFor(model=>model.State,"",new{@>="text-danger"})</div></div><div>="form-group"><div>="col-md-offset-2col-md-10"><buttontype="submit">="btnbtn-default">Create</button></div></div></div>}</div></div></div></div>对应Controller代码:[ChildActionOnly]publicPartialViewResultCreate(){varuserList=_userAppService.GetUsers();ViewBag.AssignedPersonId=newSelectList(userList.Items,"Id","Name");returnPartialView("_CreateTask");}[HttpPost][ValidateAntiForgeryToken]publicActionResultCreate(CreateTaskInputtask){varid=_taskAppService.CreateTask(task);varinput=newGetTasksInput();varoutput=_taskAppService.GetTasks(input);returnPartialView("_List",output.Tasks);}四、创建更新分部视图(_EditTask.cshtml)同样,该视图也采用异步更新方式,也采用Bootstrap-Modal,Ajax.BeginForm()技术。该PartialView绑定UpdateTaskInput模型。@modelLearningMpaAbp.Tasks.Dtos.UpdateTaskInput@{ViewBag.Title="Edit";}<div>="modalfade"id="editTask"tabindex="-1"role="dialog"aria-labelledby="editTask"data-backdrop="static"><div>="modal-dialog"role="document"><div>="modal-content"><div>="modal-header"><buttontype="button">="close"data-dismiss="modal"><spanaria-hidden="true">×</span><span>="sr-only">Close</span></button><h4>="modal-title"id="myModalLabel">EditTask</h4></div><div>="modal-body"id="modalContent">@using(Ajax.BeginForm("Edit","Tasks",newAjaxOptions(){UpdateTargetId="taskList",InsertionMode=InsertionMode.Replace,OnBegin="beginPost('#editTask')",OnSuccess="hideForm('#editTask')"})){@Html.AntiForgeryToken()<div>="form-horizontal"><h4>Task</h4><hr/>@Html.ValidationSummary(true,"",new{@>="text-danger"})@Html.HiddenFor(model=>model.Id)<div>="form-group">@Html.LabelFor(model=>model.AssignedPersonId,"AssignedPersonId",htmlAttributes:new{@>="control-labelcol-md-2"})<div>="col-md-10">@Html.DropDownList("AssignedPersonId",null,htmlAttributes:new{@>="form-control"})@Html.ValidationMessageFor(model=>model.AssignedPersonId,"",new{@>="text-danger"})</div></div><div>="form-group">@Html.LabelFor(model=>model.Title,htmlAttributes:new{@>="control-labelcol-md-2"})<div>="col-md-10">@Html.EditorFor(model=>model.Title,new{htmlAttributes=new{@>="form-control"}})@Html.ValidationMessageFor(model=>model.Title,"",new{@>="text-danger"})</div></div><div>="form-group">@Html.LabelFor(model=>model.Description,htmlAttributes:new{@>="control-labelcol-md-2"})<div>="col-md-10">@Html.EditorFor(model=>model.Description,new{htmlAttributes=new{@>="form-control"}})@Html.ValidationMessageFor(model=>model.Description,"",new{@>="text-danger"})</div></div><div>="form-group">@Html.LabelFor(model=>model.State,htmlAttributes:new{@>="control-labelcol-md-2"})<div>="col-md-10">@Html.EnumDropDownListFor(model=>model.State,htmlAttributes:new{@>="form-control"})@Html.ValidationMessageFor(model=>model.State,"",new{@>="text-danger"})</div></div><div>="form-group"><div>="col-md-offset-2col-md-10"><inputtype="submit"value="Save">="btnbtn-default"/></div></div></div>}</div></div></div></div><scripttype="text/javascript">//该段代码十分重要,确保异步调用后jquery能正确执行验证逻辑$(function(){//allowvalidationframeworktoparseDOM$.validator.unobtrusive.parse('form');});</script>后台代码:publicPartialViewResultEdit(intid){vartask=_taskAppService.GetTaskById(id);varupdateTaskDto=AutoMapper.Mapper.Map<UpdateTaskInput>(task);varuserList=_userAppService.GetUsers();ViewBag.AssignedPersonId=newSelectList(userList.Items,"Id","Name",updateTaskDto.AssignedPersonId);returnPartialView("_EditTask",updateTaskDto);}[HttpPost][ValidateAntiForgeryToken]publicActionResultEdit(UpdateTaskInputupdateTaskDto){_taskAppService.UpdateTask(updateTaskDto);varinput=newGetTasksInput();varoutput=_taskAppService.GetTasks(input);returnPartialView("_List",output.Tasks);}五,创建Index视图在首页中,我们一般会用来展示列表,并通过弹出模态框的方式来进行新增更新删除。为了使用ASP.NETMVC强视图带给我们的好处(模型绑定、输入校验等等),我们需要创建一个ViewModel来进行模型绑定。因为Abp提倡为每个不同的应用服务提供不同的Dto进行数据交互,新增对应CreateTaskInput,更新对应UpdateTaskInput,展示对应TaskDto。那我们创建的ViewModel就需要包含这几个模型,方可在一个视图中完成多个模型的绑定。1,创建视图模型(IndexViewModel)namespaceLearningMpaAbp.Web.Models.Tasks{public>IndexViewModel{///<summary>///用来进行绑定列表过滤状态///</summary>publicTaskState?SelectedTaskState{get;set;}///<summary>///列表展示///</summary>publicIReadOnlyList<TaskDto>Tasks{get;}///<summary>///创建任务模型///</summary>publicCreateTaskInputCreateTaskInput{get;set;}///<summary>///更新任务模型///</summary>publicUpdateTaskInputUpdateTaskInput{get;set;}publicIndexViewModel(IReadOnlyList<TaskDto>items){Tasks=items;}///<summary>///用于过滤下拉框的绑定///</summary>///<returns></returns>publicList<SelectListItem>GetTaskStateSelectListItems(){varlist=newList<SelectListItem>(){newSelectListItem(){Text="AllTasks",Value="",Selected=SelectedTaskState==null}};list.AddRange(Enum.GetValues(typeof(TaskState)).Cast<TaskState>().Select(state=>newSelectListItem(){Text=$"TaskState_{state}",Value=state.ToString(),Selected=state==SelectedTaskState}));returnlist;}}}2,创建视图Index视图,通过加载PartialView的形式,将列表、新增视图一次性加载进来。@usingAbp.Web.Mvc.Extensions@modelLearningMpaAbp.Web.Models.Tasks.IndexViewModel@{ViewBag.Title=L("TaskList");ViewBag.ActiveMenu="TaskList";//MatcheswiththemenunameinSimpleTaskAppNavigationProvidertohighlightthemenuitem}@sectionscripts{@Html.IncludeScript("~/Views/Tasks/index.js");}<h2>@L("TaskList")<buttontype="button">="btnbtn-primary"data-toggle="modal"data-target="#add">CreateTask</button><a>="btnbtn-primary"data-toggle="modal">"@Url.Action("RemoteCreate")"data-target="#modal"role="button">(CreateTask)使用Remote方式调用Modal进行展现</a><!--任务清单按照状态过滤的下拉框--><span>="pull-right">@Html.DropDownListFor(model=>model.SelectedTaskState,Model.GetTaskStateSelectListItems(),new{@form-controlselect2",id="TaskStateCombobox"})</span></h2><!--任务清单展示--><div>="row"id="taskList">@{Html.RenderPartial("_List",Model.Tasks);}</div><!--通过初始加载页面的时候提前将创建任务模态框加载进来-->@Html.Action("Create")<!--编辑任务模态框通过ajax动态填充到此div中--><divid="edit"></div><!--Remote方式弹出创建任务模态框--><div>="modalfade"id="modal"tabindex="-1"role="dialog"aria-labelledby="createTask"data-backdrop="static"><div>="modal-dialog"role="document"><div>="modal-content"></div></div></div>3,Remote方式创建任务讲解Remote方式就是,点击按钮的时候去加载创建任务的PartialView到指定的div中。而我们代码中另一种方式是通过@Html.Action("Create")的方式,在加载Index的视图的作为子视图同步加载了进来。感兴趣的同学自行查看源码,不再讲解。<a>="btnbtn-primary"data-toggle="modal">"@Url.Action("RemoteCreate")"data-target="#modal"role="button">(CreateTask)使用Remote方式调用Modal进行展现</a><!--Remote方式弹出创建任务模态框--><div>="modalfade"id="modal"tabindex="-1"role="dialog"aria-labelledby="createTask"data-backdrop="static"><div>="modal-dialog"role="document"><div>="modal-content"></div></div></div>4,后台代码publicActionResultIndex(GetTasksInputinput){varoutput=_taskAppService.GetTasks(input);varmodel=newIndexViewModel(output.Tasks){SelectedTaskState=input.State};returnView(model);}5,js代码(index.js)vartaskService=abp.services.app.task;(function($){$(function(){var$taskStateCombobox=$('#TaskStateCombobox');$taskStateCombobox.change(function(){getTaskList();});var$modal=$(".modal");//显示modal时,光标显示在第一个输入框$modal.on('shown.bs.modal',function(){$modal.find('input:not([type=hidden]):first').focus();});});})(jQuery);//异步开始提交时,显示遮罩层functionbeginPost(modalId){var$modal=$(modalId);abp.ui.setBusy($modal);}//异步开始提交结束后,隐藏遮罩层并清空FormfunctionhideForm(modalId){var$modal=$(modalId);var$form=$modal.find("form");abp.ui.clearBusy($modal);$modal.modal("hide");//创建成功后,要清空form表单$form[0].reset();}//处理异步提交异常functionerrorPost(xhr,status,error,modalId){if(error.length>0){abp.notify.error('Somethingisgoingwrong,pleaseretryagainlater!');var$modal=$(modalId);abp.ui.clearBusy($modal);}}functioneditTask(id){abp.ajax({url:"/tasks/edit",data:{"id":id},type:"GET",dataType:"html"}).done(function(data){$("#edit").html(data);$("#editTask").modal("show");}).fail(function(data){abp.notify.error('Somethingiswrong!');});}functiondeleteTask(id){abp.message.confirm("是否删除Id为"+id+"的任务信息",function(isConfirmed){if(isConfirmed){taskService.deleteTask(id).done(function(){abp.notify.info("删除任务成功!");getTaskList();});}});}functiongetTaskList(){var$taskStateCombobox=$('#TaskStateCombobox');varurl='/Tasks/GetList?state='+$taskStateCombobox.val();abp.ajax({url:url,type:"GET",dataType:"html"}).done(function(data){$("#taskList").html(data);});}js代码中处理了Ajax回调函数,以及任务状态过滤下拉框更新事件,编辑、删除任务代码。其中getTaskList()函数是用来异步刷新列表,对应调用的GetList()Action的后台代码如下:publicPartialViewResultGetList(GetTasksInputinput){varoutput=_taskAppService.GetTasks(input);returnPartialView("_List",output.Tasks);}六、总结至此,完成了任务的增删改查。展现层主要用到了Asp.netmvc的强类型视图、Bootstrap-Modal、Ajax异步提交技术。其中需要注意的是,在异步加载表单时,需要添加以下js代码,jquery方能进行前端验证。<scripttype="text/javascript">$(function(){//allowvalidationframeworktoparseDOM$.validator.unobtrusive.parse('form');});</script>源码已上传至Github-LearningMpaAbp,可自行参考
【.Net】