当前位置: 首页 > 编程语言 > C#

ConditionalModelStateMerge分享

时间:2023-04-10 17:47:33 C#

ConditionalModelStateMerge我实现了第二次响应“PreservemodelstateerroracrossRedirectToAction?”问题,涉及两个自定义ActionFilterAttributes的使用。我喜欢这个解决方案,它通过向需要该功能的方法添加属性来保持代码整洁。该解决方案在大多数情况下都可以正常工作,但我遇到了重复部分视图的问题。基本上我有一个部分视图使用它自己的模型,与父视图使用的模型分开。主视图中我的代码的简化版本:@for(inti=0;imodel.Address1,new{@class="form-control"})[...]当不使用自定义ActionFilterAttributes时,一切都按预期工作。每次执行分部视图时,像“model=>model.Address1”这样的lamba表达式都会从ModelState中提取正确的值。问题是当我重定向并使用自定义ActionFilterAttributes时。核心问题是,不仅更新了一个地址实例的ModelState,而且部分视图构建的所有地址的ModelState都被覆盖,因此它们包含相同的值,而不是正确的实例值。我的问题是如何修改自定义ActionFilterAttributes以便它只更新受影响的一个Address实例的ModelState,而不是所有ModelStates?我想避免向使用此属性的方法添加任何内容,以保持干净的实现。这是来自另一个问题的自定义ActionFilterAttributes代码:publicclassSetTempDataModelStateAttribute:ActionFilterAttribute{filterContext.Controller.TempData["ModelViewData.State"]=filterContext.Controller}}publicclassRestoreModelStateFromTempDataAttribute:ActionFilterAttribute{publicoverridevoidOnActionExecuting(ActionExecutingContextfilterContext){base.OnActionExecuting(filterContext);Merge((ModelStateDictionary)filterContext.Controller.TempData["ModelState"]);}}}查看此实现(benfoster)是否有效:我经常使用它并且从未遇到过问题。你正确设置属性吗?'运行上的SetTempDataModelState和运行后的SetTempDataModelState?以下是需要的4个类(导出,导入,传输和验证)ModelState[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple=false,Inheritled=falsetrue)]publicclassExportModelStateToTempDataAttribute:ModelStateTempDataTransfer{publicoverridevoidOnActionExecuted(ActionExecutedContextfilterContext){//仅在ModelState无效且我们正在执行重定向(即PRG)时复制if(!filterContext.Controller.ViewData.ModelState.IsValid&&(filterContext.Result是RedirectResult||filterContext.Result是RedirectToRouteResult)){ExportModelStateToTempData(filterContext);}base.OnActionExecuted(filterContext);}}//////用于从TempData导入ModelState的动作过滤器。///在使用./////////在遵循PRG(发布、重定向、获取)模式时很有用。///[AttributeUsage(AttributeTargets.类|AttributeTargets.Method,AllowMultiple=false,Inherited=true)]publicclassImportModelStateFromTempDataAttribute:ModelStateTempDataTransfer{publicoverridevoidOnActionExecuted(ActionExecutedContextfilterContext){//如果我们正在渲染视图/部分,则仅从TempData复制if(filterContext.ResultisViewResult){ImportModelStateFromTempData(filterContext);}else{//删除它RemoveModelStateFromTempData(filterContext);}base.OnActionExecuted(filterContext);}}[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple=false,Inherited=true)]publicabstractclassModelStateTempDataTransfer:ActionFilterAttribute{protectedstaticreadonlystringKey=typeof(ModelStateTempDataTransfer).FullName;//////将当前ModelState导出到TempData(在下一个请求时可用)。///protectedstaticvoidExportModelStateToTempData(ControllerContextcontext){context.Controller.TempData[Key]=context.Controller.ViewData.ModelState;}//////使用TempData中的值填充当前ModelState///protectedstaticvoidImportModelStateFromTempData(ControllerContextcontext){varprevModelState=context.Controller.TempData[Key]asModelStateDictionary;context.Controller.ViewData.ModelState.Merge(prevModelState);}//////从TempData中移除ModelState///protectedstaticvoidRemoveModelStateFromTempData(ControllerContextcontext){context.Controller.TempData[Key]=null;}}//////一个ActionFilter,用于在执行控制器操作之前自动验证ModelState。///如果ModelState无效,则执行重定向。假定在GET操作中使用了。///[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method,AllowMultiple=false,Inherited=true)]publicclassValidateModelStateAttribute:ModelStateTempDataTransfer{publicoverridevoidOnActionExecuting(ActionExecutingContextfilterContext){如果(!filterContext.Controller.ViewData.ModelState.IsValid){如果(filterContext.HttpContext.Request.IsAjaxRequest()){ProcessAjax(filterContext);}else{ProcessNormal(filterContext);}}base.OnActionExecuting(filterContext);}protectedvirtualvoidProcessNormal(ActionExecutingContextfilterContext){//将ModelState导出到TempData,以便在下一次请求时可用ExportModelStateToTempData(filterContext);//重定向回GET动作filterContext.Result=newRedirectToRouteResult(filterContext.RouteData.Values);}protectedvirtualvoidProcessAjax(ActionExecutingContextfilterContext){varerrors=filterContext.Controller.ViewData.ModelState.ToSerializableDictionary();varjson=newJavaScriptSerializer().Serialize(errors);//发送400状态码(错误请求)filterContext.Result=newHttpStatusCodeResult((int)HttpStatusCode.BadRequest,json);}}编辑这是一个通用(非动态过滤器)PRG模式:[HttpGet]publicasyncTaskEdit(Guidid){varcalendarEvent=awaitcalendarService.FindByIdAsync(id);如果(calendarEvent==null)返回this.RedirectToAction(c=>c.Index());varmodel=newCalendarEditViewModel(calendarEvent);ViewData.Model=模型;返回视图();}[HttpPost]publicasyncTaskEdit(Guidid,CalendarEventBindingModelbinding){if(!ModelState.IsValid)returnawaitEdit(id);varcalendarEvent=awaitcalendarService.FindByIdAsync(id);if(calendarEvent!=null){CalendarEvent模型=calendarService.Update(calendarEvent,binding);等待context.SaveChangesAsync();}返回this.RedirectToAction(c=>c.Index());目的)要避免的是删除每个postAction上的ModelState.IsValid检查,因此相同的(带有操作过滤器)将是:ID);如果(calendarEvent==null)返回this.RedirectToAction(c=>c.Index());varmodel=newCalendarEditViewModel(calendarEvent);看法数据.模型=模型;返回视图();}//ActionResult更改为RedirectToRouteResult[HttpPost,ValidateModelState]publicasyncTaskEdit(Guidid,CalendarEventBindingModelbinding){//移除ModelState.IsValid检查varcalendarEvent=awaitcalendarService.FindByIdAsync(id);if(calendarEvent!=null){CalendarEvent模型=calendarService.Update(calendarEvent,binding);等待context.SaveChangesAsync();}返回this.RedirectToAction(c=>c.Index());}这里没有更多的事情发生因此,如果您只使用ExportModelState操作过滤器,您将得到这样的后期操作:[HttpPost,ExportModelStateToTempData]publicasyncTaskEdit(Guidid,CalendarEventBindingModelbinding){if(!ModelState.IsValid)returnRedirectToAction("编辑",new{id});varcalendarEvent=awaitcalendarService.FindByIdAsync(id);if(calendarEvent!=null){CalendarEvent模型=calendarService.Update(calendarEvent,binding);等待context.SaveChangesAsync();}返回这个。RedirectToAction(c=>c.Index());这让我问你,你为什么首先要为ActionFilters烦恼?虽然我确实喜欢ValidateModelState模式(很多人不喜欢),但如果您在控制器中重定向除了一个场景并且您有其他模型状态错误,我真的看不到任何好处,让我给您一个完整性示例:[HttpPost,ValidateModelState,ExportModelStateToTempData]publicasyncTaskEdit(Guidid,CalendarEventBindingModelbinding){varcalendarEvent=awaitcalendarService.FindByIdAsync(id);}如果(!(calendarEvent.DateStart>DateTime.UtcNow.AddDays&(7))binding.DateStart!=calendarEvent.DateStart){ModelState.AddModelError("id","对不起,日期星t不能用少于7天的事件进行更新。”);returnRedirectToAction("Edit",new{id});}if(calendarEvent!=null){CalendarEventmodel=calendarService.Update(calendarEvent,binding);awaitcontext.SaveChangesAsync();}returnthis.RedirectToAction(c=>c.Index());}在上一个例子中,我使用了ValidateModelState和ExportModelState,这是因为ValidateModelState运行在ActionExecuting中,所以进入方法体Validation是之前完成,如果绑定有一些验证错误,它会自动重定向然后我有另一个检查不能在数据注释中,因为它处理加载实体并查看它是否具有正确的要求(我知道这不是最好的例子,把它想象成注册时提供的用户名是否可用),我知道远程数据注释,但它不涵盖所有情况)然后我只是根据外部因素而不是绑定我自己的错误。由于ExportModelState在ExportModelState上运行,ActionExecuted我对ModelState的所有修改都在TempData中,因此我将在HttpGetEdit操作中使用它们。我知道所有这些会让我们中的一些人对如何在Controller/PRG端执行MVC感到困惑没有好的指示。我正在尝试写一篇博客文章来涵盖所有场景和解决方案。这只是其中的1%。我希望至少我已经弄清了POST-GET工作流程的几个关键点。如果这让我有点困扰,请告诉我。很抱歉这篇文章很长。我还应该注意到,返回ActionResult的PRG与返回RedirectToRouteResult的PRG存在细微差别。如果您在出现ValidationError后使用RedirectToRouteResult刷新页面(F5),错误将不会持续存在,您将获得清晰的视图,就像您第一次输入它一样。使用ActionResult,您可以刷新并看到与错误完全相同的页面。这与ActionResult或RedirectToRouteResult返回类型无关,因为在一种情况下您总是在POST时重定向,而在另一种情况下仅在成功的POST时重定向。PRG不建议盲目地对不成功的POST进行重定向,但有些人更喜欢对每个帖子进行重定向,这需要TempData传输。以上就是C#学习教程:条件ModelState合并分享的全部内容。如果对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: