Asp.net mvc MVC控制器中重构和处理非异常错误的设计模式

Asp.net mvc MVC控制器中重构和处理非异常错误的设计模式,asp.net-mvc,design-patterns,error-handling,refactoring,controller,Asp.net Mvc,Design Patterns,Error Handling,Refactoring,Controller,在我的MVC3应用程序中,我有一个特定于每个控制器的“查询”类,该类执行域实体之间的转换,并将它们转换为视图模型。我这样做是为了保持我的控制器干净,并且更容易单独对控制器和查询进行单元测试 但是,在某些情况下,查询方法需要将非异常错误消息传递给视图(例如,找不到实体)。但是,由于我的控制器仅从查询方法接收ViewModel,而没有任何类型的返回代码,因此我发现传递此错误的仅有两个选项如下: 从查询方法引发异常,并使用Try/Catch块捕获控制器中的异常 向视图模型添加一个名为“ErrorMes

在我的MVC3应用程序中,我有一个特定于每个控制器的“查询”类,该类执行域实体之间的转换,并将它们转换为视图模型。我这样做是为了保持我的控制器干净,并且更容易单独对控制器和查询进行单元测试

但是,在某些情况下,查询方法需要将非异常错误消息传递给视图(例如,找不到实体)。但是,由于我的控制器仅从查询方法接收ViewModel,而没有任何类型的返回代码,因此我发现传递此错误的仅有两个选项如下:

  • 从查询方法引发异常,并使用Try/Catch块捕获控制器中的异常

  • 向视图模型添加一个名为“ErrorMessage”的属性,该属性由视图用于执行所需显示内容逻辑的查询方法填充

  • 因为这些不是例外情况,而且我知道我不应该使用Try/Catch来控制程序流,所以我选择使用第二种方法。虽然现在这样做还管用,但我觉得它“脏”了,原因如下:

    • 当发生错误时,控制器必须接收整个视图模型才能获取ErrorMessage属性
    • 视图必须有硬编码逻辑和两个部分来显示错误或正常内容
    • 虽然我可以将
      if(Model.ErrorMessage!=null)
      逻辑放在我的控制器中,以确定要传递哪个视图,但它仍然不像是一个“干净”的解决方案
    是否有任何设计模式可以帮助我重构代码并使其更干净

    示例视图模型:

    public class ApplicationViewModel
    {
      public string ErrorMessage { get; set; }
      public int Id { get; set; }
      public string Name { get; set; }
      // Other properties here...
    }
    
    public ActionResult Retrieve(Guid guid)
    {
      return View("Application", _applicationQueries.GetApplicationViewModel(guid));
    }
    
    public ApplicationViewModel GetApplicationViewModel(Guid guid)
    {
      var applicationViewModel = new applicationViewModel();
    
      if (!_applicationServices.Exists(guid))
      {
        applicationViewModel.ErrorMessage = "The requested application does not exist.";
        return applicationViewModel;
      }
    
      // More code here that checks things which might set the ErrorMessage property...
    
      var application = _applicationServices.GetApplicationByGuid((Guid)guid);
      Mapper.Map(grantApplication, grantApplicationViewModel);
      return grantApplicationViewModel;
    }
    
    @model MyApp.Web.Areas.Application.Models.ApplicationViewModel
    if (Model.ErrorMessage != null)
    {
      <div>@Model.ErrorMessage</div>
    }
    else
    {
      <!-- Display "normal" content here //>
    }
    
    控制器方法示例:

    public class ApplicationViewModel
    {
      public string ErrorMessage { get; set; }
      public int Id { get; set; }
      public string Name { get; set; }
      // Other properties here...
    }
    
    public ActionResult Retrieve(Guid guid)
    {
      return View("Application", _applicationQueries.GetApplicationViewModel(guid));
    }
    
    public ApplicationViewModel GetApplicationViewModel(Guid guid)
    {
      var applicationViewModel = new applicationViewModel();
    
      if (!_applicationServices.Exists(guid))
      {
        applicationViewModel.ErrorMessage = "The requested application does not exist.";
        return applicationViewModel;
      }
    
      // More code here that checks things which might set the ErrorMessage property...
    
      var application = _applicationServices.GetApplicationByGuid((Guid)guid);
      Mapper.Map(grantApplication, grantApplicationViewModel);
      return grantApplicationViewModel;
    }
    
    @model MyApp.Web.Areas.Application.Models.ApplicationViewModel
    if (Model.ErrorMessage != null)
    {
      <div>@Model.ErrorMessage</div>
    }
    else
    {
      <!-- Display "normal" content here //>
    }
    
    示例应用程序查询方法:

    public class ApplicationViewModel
    {
      public string ErrorMessage { get; set; }
      public int Id { get; set; }
      public string Name { get; set; }
      // Other properties here...
    }
    
    public ActionResult Retrieve(Guid guid)
    {
      return View("Application", _applicationQueries.GetApplicationViewModel(guid));
    }
    
    public ApplicationViewModel GetApplicationViewModel(Guid guid)
    {
      var applicationViewModel = new applicationViewModel();
    
      if (!_applicationServices.Exists(guid))
      {
        applicationViewModel.ErrorMessage = "The requested application does not exist.";
        return applicationViewModel;
      }
    
      // More code here that checks things which might set the ErrorMessage property...
    
      var application = _applicationServices.GetApplicationByGuid((Guid)guid);
      Mapper.Map(grantApplication, grantApplicationViewModel);
      return grantApplicationViewModel;
    }
    
    @model MyApp.Web.Areas.Application.Models.ApplicationViewModel
    if (Model.ErrorMessage != null)
    {
      <div>@Model.ErrorMessage</div>
    }
    else
    {
      <!-- Display "normal" content here //>
    }
    
    从Application.cshtml视图中单击以进行错误处理:

    public class ApplicationViewModel
    {
      public string ErrorMessage { get; set; }
      public int Id { get; set; }
      public string Name { get; set; }
      // Other properties here...
    }
    
    public ActionResult Retrieve(Guid guid)
    {
      return View("Application", _applicationQueries.GetApplicationViewModel(guid));
    }
    
    public ApplicationViewModel GetApplicationViewModel(Guid guid)
    {
      var applicationViewModel = new applicationViewModel();
    
      if (!_applicationServices.Exists(guid))
      {
        applicationViewModel.ErrorMessage = "The requested application does not exist.";
        return applicationViewModel;
      }
    
      // More code here that checks things which might set the ErrorMessage property...
    
      var application = _applicationServices.GetApplicationByGuid((Guid)guid);
      Mapper.Map(grantApplication, grantApplicationViewModel);
      return grantApplicationViewModel;
    }
    
    @model MyApp.Web.Areas.Application.Models.ApplicationViewModel
    if (Model.ErrorMessage != null)
    {
      <div>@Model.ErrorMessage</div>
    }
    else
    {
      <!-- Display "normal" content here //>
    }
    
    @model MyApp.Web.Areas.Application.Models.ApplicationViewModel
    如果(Model.ErrorMessage!=null)
    {
    @Model.ErrorMessage
    }
    其他的
    {
    
    您可以将
    ModelState
    实例传递到
    querys
    层,它会注意添加错误:

    public ApplicationViewModel GetApplicationViewModel(Guid guid, ModelStateDictionary modelState)
    {
        var applicationViewModel = new applicationViewModel();
        if (!_applicationServices.Exists(guid))
        {
            modelState.AddModelError("", "The requested application does not exist.");
            return applicationViewModel;
        }
    
        // More code here that checks things which might set the ErrorMessage property...
    
        var application = _applicationServices.GetApplicationByGuid((Guid)guid);
        Mapper.Map(grantApplication, grantApplicationViewModel);
        return grantApplicationViewModel;
    }
    
    在你看来:

    @model MyApp.Web.Areas.Application.Models.ApplicationViewModel
    
    @Html.ValidationSummary()
    
    @if (ViewData.ModelState.IsValid)
    {
        <!-- Display "normal" content here //>
    }
    
    @model MyApp.Web.Areas.Application.Models.ApplicationViewModel
    @Html.ValidationSummary()
    @if(ViewData.ModelState.IsValid)
    {
    
    事实上,我认为你得到的非常好。你是对的,你不应该对这种非异常错误使用try/catch。我不会担心传回整个视图模型:这并不是说你在返回错误之前用大量数据填充它。至于必须在视图中切换,真的没有办法得到aro而且:如果你要对错误条件进行自定义显示,对有效情况进行不同的显示,你必须有一个条件。我能想到的唯一其他方法是使用多态性。谢谢Darin。我喜欢你的方法,我会使用它。