【问题标题】:How to keep using ModelState with RedirectToAction in ASP.NET MVC 6?如何在 ASP.NET MVC 6 中继续使用 ModelState 和 RedirectToAction?
【发布时间】:2016-06-29 03:22:22
【问题描述】:

我有一个删除对象的方法。删除不属于自己的视图,是“EditReport”中的“Delete”按钮。成功移除“报告”上的重定向后。

[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。我从这里拿的:https://stackoverflow.com/a/12024227/3878213

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 的定义。

【问题讨论】:

    标签: c# asp.net-mvc asp.net-core asp.net-core-mvc asp.net-core-1.0


    【解决方案1】:

    感谢answer,我意识到需要创建自己的代码 ASP.NET Core 1.0 (Full .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(完整的.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();
            }
        }
    

    【讨论】:

    • 应该有一个检查来防止非错误出现在SetTempDataModelStateAttributevar listError = modelState.ToDictionary(m =&gt; m.Key, m =&gt; m.Value.Errors 应该是modelState.Where(x =&gt; x.Value.Errors.Any()).ToDictionary(m...
    • 在这里使用await next(); 是不正确的,因为它会导致该方法被多次命中。
    【解决方案2】:

    使代码编译的修复方法如下,但似乎 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"]);
            }
        }
    }
    

    【讨论】:

    • 添加到 Sessions 项目。虽然我无法解决错误的问题:InvalidOperationException: The 'Microsoft.AspNet.Mvc.ViewFeatures.SessionStateTempDataProvider' cannot serialize an object of type 'Microsoft.AspNet.Mvc.ModelBinding.ModelStateDictionary' to session state.
    • 似乎 ASP.NET Core 不支持序列化模型状态,并且没有计划改变它。我已经更新了我的答案以反映这一点。
    • 正确地将 ModelState 转换为字符串 (json) 并存储在 TempData 中?
    • 您不能序列化模型状态,包括将其序列化为 JSON。如果您仍想这样做,则必须手动对其进行序列化。
    • 感谢您的信息。这是我的解决方案stackoverflow.com/a/35987804/3878213
    猜你喜欢
    • 1970-01-01
    • 2011-06-06
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多