【问题标题】:Error handling and try/catch blocks with asynchronous methods错误处理和使用异步方法的 try/catch 块
【发布时间】:2018-03-21 17:10:02
【问题描述】:

我正在 Visual Studio 2017 社区版中编写一个 ASP.Net Core 2 MVC 应用程序。在处理异步方法时,我无法理解 try-catch 块的行为方式。下面是两个 sn-ps,一个控制器中的动作和该动作调用的方法。

首先让我说该程序按预期工作。问题是当我故意创建错误时,我希望中间件显示预定的错误页面。这也可以在相同代码的同步版本中按预期工作。

使用此异步版本,浏览器不会返回任何错误,甚至不会返回 HTTP500 内部服务器错误页面,它只是一直在等待某些事情发生。如果我再查看 WebServer 输出,我会看到异常被抛出,我什至读到错误页面视图正在运行,而实际上它没有运行。

有人能解释一下我在这里缺少什么吗?谢谢!

这是行动。我跳过了方法中的很多内容,因为它应该是无关紧要的,而且真的很长。另外,我认为这无关紧要,但是我知道什么...所以请注意,此操作会返回部分视图。动作本身由另一个动作中的 ajax 请求调用。

     // Variance Report -- POST
     [HttpPost]
     [Authorize]
     [ValidateAntiForgeryToken]
     public async Task<IActionResult> Variance(VarianceModel model)
     {
         try
         {
             // Get the report data
             var varianceReport = await _report.GetVarianceReportAsync(model);

             // String that will display the current selection
             ViewBag.Parameters = model.parameterDescription;

             // Return the partial view
             return PartialView("_VariancePartial", varianceReport);
         }
         catch (Exception)
         {
             throw;
         }
     }

这里是被调用的方法:

     // REPORT
     public async Task<VarianceModel> GetVarianceReportAsync(VarianceModel model)
     {
         try
         { 
             // Do a lot of stuff here... then I deliberately try to
             // divide by zero so as to get an error:
                         try
                         {
                             VariancePercent = (VarianceValue / 0)
                         }
                         catch (Exception)
                         {
                             throw;
                         }
             // Do more stuff here as well...
                 }
             return model;
         }
         catch (Exception)
         {
             throw;
         }
     }

最后,这是来自网络服务器的输出:

[...bla bla bla...]
WebApp> fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0]
WebApp>       An unhandled exception has occurred: Attempted to divide by zero.
WebApp> System.DivideByZeroException: Attempted to divide by zero.
[...bla bla bla...]
WebApp> info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
WebApp>       Executing action method WebApp.Controllers.HomeController.Error ( WebApp) with arguments ((null)) - ModelState is Valid
WebApp> info: 
Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ViewResultExecutor[1]
WebApp>       Executing ViewResult, running view at path /Views/Shared/Error.cshtml.
WebApp> info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
WebApp>       Executed action WebApp.Controllers.HomeController.Error (WebApp) in 1.8921ms
WebApp> info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
WebApp>       Request finished in 66679.065ms 500 text/html; charset=utf-8

【问题讨论】:

  • 当您说“该操作本身由另一个操作中的 ajax 请求调用”时,您是什么意思。 ?
  • 我的意思是有一个名为“Variance”的动作,它使用 HttpGet 方法返回一个视图。在该视图中,参数被设置并保存在模型中,该模型是由发布到上述操作的 Ajax 请求传递的模型。此操作在无错误时返回显示在原始主视图中的局部视图。我希望我自己解释...
  • 如果您在网络服务器输出中看到此内容,则服务器已完成工作。它实际上已经返回了响应。如果浏览器仍在等待,则客户端出现故障。也许发布你在那里运行的代码。
  • @ChrisPratt 我没有做任何花哨的客户端......只有一个视图在等待它的部分......我可能已经超出了我的深度:(

标签: asp.net-mvc async-await visual-studio-2017 try-catch asp.net-core-2.0


【解决方案1】:

您正在抛出一个异常,但该页面无法显示它。 您应该返回一个实际的 HTTP 响应,而不是仅仅抛出异常:

[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Variance(VarianceModel model)
{
    try
    {
        // Get the report data
        var varianceReport = await _report.GetVarianceReportAsync(model);

        // String that will display the current selection
        ViewBag.Parameters = model.parameterDescription;

        // Return the partial view
        return PartialView("_VariancePartial", varianceReport);
    }
    catch (Exception ex)
    {
        return new ObjectResult(ex);
    }
}

// REPORT
public async Task<VarianceModel> GetVarianceReportAsync(VarianceModel model)
{
    try
    {
        // divide by zero so as to get an error:
        VariancePercent = (VarianceValue / 0);
        return model;
    }
    catch (Exception)
    {
        throw;
    }
}

但是,这不会是一个非常干净的响应。理想情况下,您应该为错误状态创建部分视图并返回:

public async Task<IActionResult> Variance(VarianceModel model)
{
    try
    {
        // Get the report data
        var varianceReport = await _report.GetVarianceReportAsync(model);

        // String that will display the current selection
        ViewBag.Parameters = model.parameterDescription;

        // Return the partial view
        return PartialView("_VariancePartial", varianceReport);
    }
    catch (Exception ex)
    {
        return PartialView("_ErrorPartial", ex);
    }
}

【讨论】:

  • 我错误地认为抛出异常总是会导致默认错误页面,无论如何。我没有考虑到,因为预期的结果是部分视图,所以错误页面也应该是部分的。您的解决方案在第一次尝试时效果很好。永远感激,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多