Asp.net mvc asp.net mvc控制器发布最佳实践

Asp.net mvc asp.net mvc控制器发布最佳实践,asp.net-mvc,asp.net-mvc-3,controller,Asp.net Mvc,Asp.net Mvc 3,Controller,我对“最佳实践”控制器使用问题有点困惑 我典型的代码外观 public ActionResult Edit(int reportId,FormCollection formCollection) { try { var report = _dbContext.EmployeeReports.Find(reportId); if (TryUpdateModel(report))

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

我典型的代码外观

    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”或简单调用模型更好。是有效的,在控制器中捕获异常是个好主意


谢谢

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

[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");
}
[HttpPost]
公共操作结果编辑(ReportViewModel ReportViewModel)
{
如果(!ModelState.IsValid)
{
//存在验证错误=>重新显示表单
//以便用户可以修复它们
返回视图(reportViewModel);
}
//在这个阶段,视图模型是有效的=>我们可以
//将其映射回域模型并传递到存储库
//处理
//获取要更新的域模型
var report=_repository.Get(reportViewModel.Id);
//从视图模型属性映射域模型属性
//在这个例子中,我使用AutoMapper
Map(reportViewModel,report);
//执行更新
_更新(报告);
//update wen fine=>我们可以重定向回list操作
返回重定向到操作(“列表”);
}

因此,正如您所看到的,没有
FormCollection
、没有
TryUpdateModel
、没有
UpdateModel
、没有
try/catch
这取决于您是否期望并计划处理异常

我通常的做法是:

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");
}

我尝试在代码中使用所有这些模型,以在问题出现之前捕获问题。

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


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

TryUpdateModel将忽略任何异常,如果出现问题,将返回false。UpdateModel将允许抛出异常。嗯,有趣的答案。关于在我的应用程序中使用automapper,我想已经很久了。顺便说一句,在大型模型中,我也使用viewmodels。这种方法不解决过度发布攻击。@UserControl,实际上它解决了它,因为视图模型将只包含用户允许修改的属性(视图中有输入字段的属性)。AutoMapper的
Map
方法将只更新域模型上的那些属性,其他属性保持不变,从而解决了如果您直接使用域模型,应用程序可能会遇到的批量分配漏洞。谢谢您的回答。有趣的解决方案。我还应该提到,对于模型验证,如果有聚合类(由其他类组成的类)使用[Required]之类的标记,则不会完全正常工作。我通常制作自己的模型状态检查器,并用调用布尔方法检查细节来替换if(!ModelState.IsValid())。