【问题标题】:Should I use TempData or RedirectToAction?我应该使用 TempData 还是 RedirectToAction?
【发布时间】:2013-12-24 03:19:04
【问题描述】:

我的控制器上有一个删除操作。它会检查用户是否真的被允许删除。

我的问题是,如果他们不允许删除:

我是否应该重定向回我的索引操作(列出他们可以删除的所有文件)并在 TempData 中向其传递一条错误消息,说“您不允许删除此资源”。

我应该选择他们可以删除的所有文件,列出它们并在删除操作中全部显示错误吗?

最佳做法是什么?

注意:我不关心授权/身份验证。

【问题讨论】:

  • 也许只是不让他们在不允许的项目上单击删除,而您根本不必处理这种情况?我意识到这并不总是很方便......
  • 您使用什么作为主键 -> 整数或 GUID ?
  • 您是在检查每个项目的删除权限,还是检查用户是否可以执行一般删除操作?
  • 我正在检查一些任意条件,与执行操作的用户权限无关。我已经更新了原来的问题。

标签: asp.net-mvc


【解决方案1】:

假设删除操作是通过 HTTP 发布命中的,Post/Redirect/Get 通常是这里的最佳做法,以防止重复发布,所以我会选择使用临时数据进行重定向。在这种特殊情况下,重复发布可能并不危险,但在其他条件相同的情况下,请选择一致性。

【讨论】:

  • 根据我的阅读 - 人们似乎同意,如果您不更新服务器上的数据,这对 PGR 不利。
  • 我不知道我会同意。就正确性而言,我认为这并不重要。在 ASP.NET MVC 中,将 ModelState 复制到 TempData 并重定向是一种非常常见的模式。 making that happen automatically 甚至还有解决方案。
  • 是的 - 我也不同意我是否同意诚实:)
【解决方案2】:

使用 Post/Redirect/Get,这里是过滤器属性(不记得我在哪里找到的):

/// <summary>
/// When a RedirectToRouteResult is returned from an action, anything in the ViewData.ModelState dictionary will be copied into TempData.
/// When a ViewResultBase is returned from an action, any ModelState entries that were previously copied to TempData will be copied back to the ModelState dictionary.
/// </summary>
public class ModelStateToTempDataAttribute : ActionFilterAttribute
{
    public const string TempDataKey = "__MvcContrib_ValidationFailures__";

    /// <summary>
    /// When a RedirectToRouteResult is returned from an action, anything in the ViewData.ModelState dictionary will be copied into TempData.
    /// When a ViewResultBase is returned from an action, any ModelState entries that were previously copied to TempData will be copied back to the ModelState dictionary.
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var modelState = filterContext.Controller.ViewData.ModelState;

        var controller = filterContext.Controller;

        if (filterContext.Result is ViewResultBase)
        {
            //If there are failures in tempdata, copy them to the modelstate
            CopyTempDataToModelState(controller.ViewData.ModelState, controller.TempData);
            return;
        }

        //If we're redirecting and there are errors, put them in tempdata instead (so they can later be copied back to modelstate)
        if ((filterContext.Result is RedirectToRouteResult || filterContext.Result is RedirectResult) && !modelState.IsValid)
        {
            CopyModelStateToTempData(controller.ViewData.ModelState, controller.TempData);
        }
    }

    private void CopyTempDataToModelState(ModelStateDictionary modelState, TempDataDictionary tempData)
    {
        if (!tempData.ContainsKey(TempDataKey)) return;

        var fromTempData = tempData[TempDataKey] as ModelStateDictionary;
        if (fromTempData == null) return;

        foreach (var pair in fromTempData)
        {
            if (modelState.ContainsKey(pair.Key))
            {
                modelState[pair.Key].Value = pair.Value.Value;

                foreach (var error in pair.Value.Errors)
                {
                    modelState[pair.Key].Errors.Add(error);
                }
            }
            else
            {
                modelState.Add(pair.Key, pair.Value);
            }
        }
    }

    private static void CopyModelStateToTempData(ModelStateDictionary modelState, TempDataDictionary tempData)
    {
        tempData[TempDataKey] = modelState;
    }
}

您需要做的就是用“ModelStateToTempData”标记您的操作(在两个操作中:使用 HttpGet 和 HttpPost 进行市场)。像这样(我项目中的代码):

    [ModelStateToTempData]
    public ActionResult Login()
    {
        if(Request.IsAuthenticated)
        {
            return View("AlreadyLoggedIn");
        }

        return View();
    }

    [HttpPost, ValidateAntiForgeryToken, ModelStateToTempData]
    public ActionResult Login(LoginViewModel viewModel)
    {
        if(ModelState.IsValid)
        {
            // other logic here
        }
        return RedirectToRoute("Login");
    }

路线配置(以防万一):

    routes.MapRoute("Login", "login", new { controller = "Login", action = "Login" });

【讨论】:

    猜你喜欢
    • 2012-04-28
    • 2017-05-20
    • 2022-08-18
    • 1970-01-01
    • 2018-09-05
    • 1970-01-01
    • 2015-10-16
    • 2023-03-06
    • 2013-02-20
    相关资源
    最近更新 更多