【问题标题】:asp.net mvc controller post best practicesasp.net mvc 控制器发布最佳实践
【发布时间】:2013-10-02 19:30:10
【问题描述】:

我对使用问题的“最佳实践”控制器有点困惑。

我的典型代码外观

    public ActionResult Edit(int reportId,FormCollection formCollection)
    {
        try
        {
            var report = _dbContext.EmployeeReports.Find(reportId);

            if (TryUpdateModel(report))
            {
                _employeeReportService.Update(report);
                return RedirectToAction("List");
            }

            return View("Edit", report);
        }
        catch (Exception)
        {
            // some logging etc
            return RedirectToAction("List");                
        }

那么,最好使用“TryUpdateModel”或仅使用“UpdateModel”或简单调用 Model.IsValid,并且在控制器中捕获异常是个好主意?

谢谢

【问题讨论】:

  • TryUpdateModel 将吞下任何异常并在出现问题时返回 false。 UpdateModel 将允许抛出异常。

标签: asp.net-mvc asp.net-mvc-3 controller


【解决方案1】:

这是我更喜欢的另一种方式:

[HttpPost]
public ActionResult Edit(ReportViewModel reportViewModel)
{
    if (!ModelState.IsValid)
    {
        // there were validation errors => redisplay the form
        // so that the user can fix them
        return View(reportViewModel);
    }

    // At this stage the view model is valid => we can
    // map it back to a domain model and pass to the repository 
    // for processing

    // Fetch the domain model that we want to update
    var report = _repository.Get(reportViewModel.Id);

    // map the domain model properties from the view model properties
    // in this example I use AutoMapper
    Mapper.Map<ReportViewModel, Report>(reportViewModel, report);

    // perform update
    _repository.Update(report);

    // the update wen fine => we can redirect back to the list action
    return RedirectToAction("List");
}

所以,你可以看到没有FormCollection,没有TryUpdateModel,没有UpdateModel,没有try/catch

【讨论】:

  • 嗯,有趣的答案。在我的应用程序中使用自动映射器我想了很长时间。顺便说一句,在大型模型中我也使用视图模型。
  • 该方法没有解决过度发布攻击。
  • @UserControl,实际上它确实解决了这个问题,因为视图模型将仅包含 允许 用户修改的属性(您在其中输入字段的属性)风景)。 AutoMapper 的Map 方法将只更新域模型上的那些属性,而其他属性保持不变,从而解决如果您直接使用域模型,您的应用程序可能会遭受的批量分配漏洞。
【解决方案2】:

这取决于您是否期望并计划处理异常。

我通常的做法是:

public ActionResult foobar(FormCollection formCollection)
{
    //Keep this out of the try catch scope in case you need to pass it
    // to the next method.
    Model model = new Model();

    try
    {
        if(!TryUpdateModel(model)
        {
            //Update Failed so fix it and redirect
            return redirectToAction("fixit");
        }
        if(!ModelState.IsValid())
        {
            //Update worked but model state was invalid, return to page to correct 
            //model validation errors
            return View("foobar", model);
        }
        //Update Succeeded so do other stuff
    }
    catch(Exception ex)
    {
        //Deal with Exception
        return redirectToAction("ErrorView", "ErrorController");
    }

    return redirectToAction("NextStep");
}

我尝试在我的代码中使用所有这些来尝试在每个问题破坏某些东西之前抓住它。

【讨论】:

  • 感谢您的回答。有趣的解决方案。
  • 我还应该提到,对于模型验证,如果您有聚合类(由其他类组成的类),使用像 [Required] 这样的标签就不能很好地工作。我通常制作自己的模型状态检查器,并将 if(!ModelState.IsValid()) 替换为调用布尔方法来检查细节。
【解决方案3】:

根据我的意见,您应该始终使用视图模型而不是 formcollection 以避免发布不足和过度发布问题。因此,在我看来,最佳实践是使用视图模型来呈现视图,并使用一种发布/获取模型来准确绑定您希望用户发布到/从操作中获取的内容。

这可能是一些额外的工作,并且某些视图模型看起来与您在控制器操作中用于绑定的模型非常相似,但我会说“安全大于便利”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 2011-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多