在 ASP.NET Core 1.0 中将 ModelState 与 RedirectToAction 异步使用
Async using ModelState with RedirectToAction in ASP.NET Core 1.0
我有一个删除对象的方法。删除不拥有视图,并且是 "EditReport" 中的一个 "Delete" 按钮。成功删除 "Report".
上的重定向后
[HttpPost]
[Route("{reportId:int}")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteReport(int reportId)
{
var success = await _reportService.DeleteReportControlAsync(reportId);
if (success == false)
{
ModelState.AddModelError("Error", "Messages");
return RedirectToAction("EditReport");
}
ModelState.AddModelError("OK", "Messages");
return RedirectToAction("Report");
}
在 ASP.NET Core 1.0(完整的 .NET Framework)中,我使用以下属性在方法之间保存 ModelState。我从这里拿走了:
我最近转为对控制器、服务和存储库使用异步方法。
在我看来,action 的属性也应该是异步的。
最初,我将代码属性重写如下:
public class SetTempDataModelStateAttribute : Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate next)
{
var controller = filterContext.Controller as Controller;
var modelState = controller?.ViewData.ModelState;
if (modelState != null)
{
var listError = modelState.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 : Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate 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();
}
}
我觉得这很合乎逻辑。但是这段代码并不像我预期的那样工作。
但以下异步属性工作正常:
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.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();
}
}
请问这两个选项哪个更正确?为什么第一个选项不起作用?
Please tell me which of the two options more correct.
选项二更正确,因为它确实有效 - 如您所见。如果你不打算从它继承,他们就会做到 sealed
。在这种情况下使用 ActionFilterAttribute
似乎是合适的。事实上 quick look @ the repo 揭示了这实际上是一种非常常见的方法。
Why does the first option not work?
它没有调用 base
调用。关键是 base
调用中可能存在您的自定义实现中缺少的代码。看看 here.
我有一个删除对象的方法。删除不拥有视图,并且是 "EditReport" 中的一个 "Delete" 按钮。成功删除 "Report".
上的重定向后[HttpPost]
[Route("{reportId:int}")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteReport(int reportId)
{
var success = await _reportService.DeleteReportControlAsync(reportId);
if (success == false)
{
ModelState.AddModelError("Error", "Messages");
return RedirectToAction("EditReport");
}
ModelState.AddModelError("OK", "Messages");
return RedirectToAction("Report");
}
在 ASP.NET Core 1.0(完整的 .NET Framework)中,我使用以下属性在方法之间保存 ModelState。我从这里拿走了:
我最近转为对控制器、服务和存储库使用异步方法。 在我看来,action 的属性也应该是异步的。 最初,我将代码属性重写如下:
public class SetTempDataModelStateAttribute : Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate next)
{
var controller = filterContext.Controller as Controller;
var modelState = controller?.ViewData.ModelState;
if (modelState != null)
{
var listError = modelState.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 : Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext filterContext, ActionExecutionDelegate 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();
}
}
我觉得这很合乎逻辑。但是这段代码并不像我预期的那样工作。 但以下异步属性工作正常:
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.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();
}
}
请问这两个选项哪个更正确?为什么第一个选项不起作用?
Please tell me which of the two options more correct.
选项二更正确,因为它确实有效 - 如您所见。如果你不打算从它继承,他们就会做到 sealed
。在这种情况下使用 ActionFilterAttribute
似乎是合适的。事实上 quick look @ the repo 揭示了这实际上是一种非常常见的方法。
Why does the first option not work?
它没有调用 base
调用。关键是 base
调用中可能存在您的自定义实现中缺少的代码。看看 here.