如何在 ASP.NET MVC 6 中继续使用 ModelState 和 RedirectToAction?
How to keep using ModelState with RedirectToAction in ASP.NET MVC 6?
我有一个删除对象的方法。移除不拥有视图,并且是 "EditReport" 中的一个 "Delete" 按钮。成功删除 "Report".
上的重定向后
[HttpPost]
[Route("{reportId:int}")]
[ValidateAntiForgeryToken]
public IActionResult DeleteReport(int reportId)
{
var success = _reportService.DeleteReportControl(reportId);
if (success == false)
{
ModelState.AddModelError("Error", "Messages");
return RedirectToAction("EditReport");
}
ModelState.AddModelError("OK", "Messages");
return RedirectToAction("Report");
}
在 ASP.NET MVC 5 中,我使用以下属性在方法之间保存 ModelState。我从这里拿走了:
public class SetTempDataModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
filterContext.Controller.TempData["ModelState"] =
filterContext.Controller.ViewData.ModelState;
}
}
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
if (filterContext.Controller.TempData.ContainsKey("ModelState"))
{
filterContext.Controller.ViewData.ModelState.Merge(
(ModelStateDictionary)filterContext.Controller.TempData["ModelState"]);
}
}
}
但是在ASP.NET MVC 6 RC 1 (ASP.NET Core 1.0)中,这段代码不起作用。
filterContext.Controller 中的错误不包含 TempData 和 ViewData 的定义。
使代码编译的修复如下,但 ASP.NET Core 似乎不支持序列化模型状态(由于 ModelStateEntry
包含永远无法序列化的异常)。
因此,您无法序列化 TempData
中的模型状态。正如 this GitHub issue 中所解释的那样,似乎没有改变这种行为的计划。
ActionExecutingContext
中的Controller
属性类型为object
。这是因为 ASP.NET Core 中的控制器不需要继承自 Controller
,因此它们没有通用的基类型。
为了访问 TempData
属性,您必须先将其转换为 Controller
。那么您的属性可能如下所示:
public class SetTempDataModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
Controller controller = filterContext.Controller as Controller;
if (controller != null)
{
controller.TempData["ModelState"] = controller.ViewData.ModelState;
}
}
}
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
Controller controller = filterContext.Controller as Controller;
if (controller != null & controller.TempData.ContainsKey("ModelState"))
{
controller.ViewData.ModelState.Merge(
(ModelStateDictionary)controller.TempData["ModelState"]);
}
}
}
感谢 ,我意识到需要创建自己的代码 ASP.NET Core 1.0(完整的 .NET Framework 4.6.2)
public class SetTempDataModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var controller = filterContext.Controller as Controller;
var modelState = controller?.ViewData.ModelState;
if (modelState != null)
{
var listError = modelState.Where(x => x.Value.Errors.Any())
.ToDictionary(m => m.Key, m => m.Value.Errors
.Select(s => s.ErrorMessage)
.FirstOrDefault(s => s != null));
controller.TempData["ModelState"] = JsonConvert.SerializeObject(listError);
}
}
}
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
var controller = filterContext.Controller as Controller;
var tempData = controller?.TempData?.Keys;
if (controller != null && tempData != null)
{
if (tempData.Contains("ModelState"))
{
var modelStateString = controller.TempData["ModelState"].ToString();
var listError = JsonConvert.DeserializeObject<Dictionary<string, string>>(modelStateString);
var modelState = new ModelStateDictionary();
foreach (var item in listError)
{
modelState.AddModelError(item.Key, item.Value ?? "");
}
controller.ViewData.ModelState.Merge(modelState);
}
}
}
}
代码的异步版本ASP.NET Core 1.0 (Full .NET Framework 4.6.2)
public class SetTempDataModelStateAttribute : ActionFilterAttribute
{
public override async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate next)
{
await base.OnActionExecutionAsync(filterContext, next);
var controller = filterContext.Controller as Controller;
var modelState = controller?.ViewData.ModelState;
if (modelState != null)
{
var listError = modelState.Where(x => x.Value.Errors.Any())
.ToDictionary(m => m.Key, m => m.Value.Errors
.Select(s => s.ErrorMessage)
.FirstOrDefault(s => s != null));
var listErrorJson = await Task.Run(() => JsonConvert.SerializeObject(listError));
controller.TempData["ModelState"] = listErrorJson;
}
await next();
}
}
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
{
public override async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate next)
{
await base.OnActionExecutionAsync(filterContext, next);
var controller = filterContext.Controller as Controller;
var tempData = controller?.TempData?.Keys;
if (controller != null && tempData != null)
{
if (tempData.Contains("ModelState"))
{
var modelStateString = controller.TempData["ModelState"].ToString();
var listError = await Task.Run(() =>
JsonConvert.DeserializeObject<Dictionary<string, string>>(modelStateString));
var modelState = new ModelStateDictionary();
foreach (var item in listError)
{
modelState.AddModelError(item.Key, item.Value ?? "");
}
controller.ViewData.ModelState.Merge(modelState);
}
}
await next();
}
}
我有一个删除对象的方法。移除不拥有视图,并且是 "EditReport" 中的一个 "Delete" 按钮。成功删除 "Report".
上的重定向后[HttpPost]
[Route("{reportId:int}")]
[ValidateAntiForgeryToken]
public IActionResult DeleteReport(int reportId)
{
var success = _reportService.DeleteReportControl(reportId);
if (success == false)
{
ModelState.AddModelError("Error", "Messages");
return RedirectToAction("EditReport");
}
ModelState.AddModelError("OK", "Messages");
return RedirectToAction("Report");
}
在 ASP.NET MVC 5 中,我使用以下属性在方法之间保存 ModelState。我从这里拿走了:
public class SetTempDataModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
filterContext.Controller.TempData["ModelState"] =
filterContext.Controller.ViewData.ModelState;
}
}
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
if (filterContext.Controller.TempData.ContainsKey("ModelState"))
{
filterContext.Controller.ViewData.ModelState.Merge(
(ModelStateDictionary)filterContext.Controller.TempData["ModelState"]);
}
}
}
但是在ASP.NET MVC 6 RC 1 (ASP.NET Core 1.0)中,这段代码不起作用。
filterContext.Controller 中的错误不包含 TempData 和 ViewData 的定义。
使代码编译的修复如下,但 ASP.NET Core 似乎不支持序列化模型状态(由于 ModelStateEntry
包含永远无法序列化的异常)。
因此,您无法序列化 TempData
中的模型状态。正如 this GitHub issue 中所解释的那样,似乎没有改变这种行为的计划。
ActionExecutingContext
中的Controller
属性类型为object
。这是因为 ASP.NET Core 中的控制器不需要继承自 Controller
,因此它们没有通用的基类型。
为了访问 TempData
属性,您必须先将其转换为 Controller
。那么您的属性可能如下所示:
public class SetTempDataModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
Controller controller = filterContext.Controller as Controller;
if (controller != null)
{
controller.TempData["ModelState"] = controller.ViewData.ModelState;
}
}
}
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
Controller controller = filterContext.Controller as Controller;
if (controller != null & controller.TempData.ContainsKey("ModelState"))
{
controller.ViewData.ModelState.Merge(
(ModelStateDictionary)controller.TempData["ModelState"]);
}
}
}
感谢
public class SetTempDataModelStateAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
var controller = filterContext.Controller as Controller;
var modelState = controller?.ViewData.ModelState;
if (modelState != null)
{
var listError = modelState.Where(x => x.Value.Errors.Any())
.ToDictionary(m => m.Key, m => m.Value.Errors
.Select(s => s.ErrorMessage)
.FirstOrDefault(s => s != null));
controller.TempData["ModelState"] = JsonConvert.SerializeObject(listError);
}
}
}
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
var controller = filterContext.Controller as Controller;
var tempData = controller?.TempData?.Keys;
if (controller != null && tempData != null)
{
if (tempData.Contains("ModelState"))
{
var modelStateString = controller.TempData["ModelState"].ToString();
var listError = JsonConvert.DeserializeObject<Dictionary<string, string>>(modelStateString);
var modelState = new ModelStateDictionary();
foreach (var item in listError)
{
modelState.AddModelError(item.Key, item.Value ?? "");
}
controller.ViewData.ModelState.Merge(modelState);
}
}
}
}
代码的异步版本ASP.NET Core 1.0 (Full .NET Framework 4.6.2)
public class SetTempDataModelStateAttribute : ActionFilterAttribute
{
public override async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate next)
{
await base.OnActionExecutionAsync(filterContext, next);
var controller = filterContext.Controller as Controller;
var modelState = controller?.ViewData.ModelState;
if (modelState != null)
{
var listError = modelState.Where(x => x.Value.Errors.Any())
.ToDictionary(m => m.Key, m => m.Value.Errors
.Select(s => s.ErrorMessage)
.FirstOrDefault(s => s != null));
var listErrorJson = await Task.Run(() => JsonConvert.SerializeObject(listError));
controller.TempData["ModelState"] = listErrorJson;
}
await next();
}
}
public class RestoreModelStateFromTempDataAttribute : ActionFilterAttribute
{
public override async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate next)
{
await base.OnActionExecutionAsync(filterContext, next);
var controller = filterContext.Controller as Controller;
var tempData = controller?.TempData?.Keys;
if (controller != null && tempData != null)
{
if (tempData.Contains("ModelState"))
{
var modelStateString = controller.TempData["ModelState"].ToString();
var listError = await Task.Run(() =>
JsonConvert.DeserializeObject<Dictionary<string, string>>(modelStateString));
var modelState = new ModelStateDictionary();
foreach (var item in listError)
{
modelState.AddModelError(item.Key, item.Value ?? "");
}
controller.ViewData.ModelState.Merge(modelState);
}
}
await next();
}
}