首页 > 解决方案 > 如何让我的 asp.netcore JsonResult 序列化到我的动作控制器内的主体,以便我可以捕获异常并计时其执行?

问题描述

我有一个如下所示的控制器操作:

[HttpGet]
public async Task<IActionResult> Query(CancellationToken ct, string query) 
{
  var sw = new StopWatch();
  sw.Start();

  try {
    IEnumerable<object> shortInfo = someObject.Query(query, ct).Distinct();
    return new JsonResult(
        // note that the next line still returns an IEnumerable, and does not execute yet
        // shortInfo has not yet begun enumeration either.
        shortInfo.Select(si => SomeSelectFunction(si))
    );
  }
  catch (Exception e)
  {
    return StatusCode(499);
  }
  finally
  {
    sw.Stop();
    Debug.WriteLine($"Query took {sw.ElapsedMilliseconds / 1000.0} sec");
  }
}

当我运行我的代码时,执行的时间非常短,并且还没有发生任何枚举。此外,我无法捕获 someObject.Query 由于取消而引发的任何异常,也无法捕获由于 SomeSelectFunction() 引发的任何异常,这也可能非常复杂。

这样做的好处是 JsonResult 被枚举并直接序列化到响应正文中,而无需物化一堆对象。

相反,我将 JsonResult 中的行更改为

        shortInfo.Select(si => SomeSelectFunction(si)).ToList()

然后我可以正确计时并捕获异常,但代价是在序列化之前实现整个列表。

问题:有什么方法可以得到延迟序列化的好处,并且仍然能够对查询函数的总持续时间进行计时。有没有办法将结果序列化到这个函数内部的响应体中,并且仍然将 json 作为 json 返回?

标签: c#asp.net-core

解决方案


考虑使用过滤器实现,允许您挂钩执行之前和之后的顺序。例如

   public class EndpointTimingMetricFilter : IActionFilter
   {
      public void OnActionExecuting(ActionExecutingContext context)
      {
         context.HttpContext.Items["timer"] = Stopwatch.StartNew();
      }

      public void OnActionExecuted(ActionExecutedContext context)
      {
         if (!(context.HttpContext.Items["timer"] is Stopwatch sw))
         {
            return;
         }

         sw.Stop();

         var endpointId = GetEndpointId(context);

         Debug.WriteLine($"Query took {sw.ElapsedMilliseconds / 1000.0} sec to execute for endpoint {endpointId}"); 
      }

      private static string GetEndpointId(ActionContext context)
      {
         var template = context.ActionDescriptor.AttributeRouteInfo.Template;
         var method   = context.HttpContext.Request.Method;
         return method + " - " + template;
      }
   }

然后,这为您提供了一个横切关注点,您可以将其应用于任何端点,并将此样板代码保留在您的主控制器操作之外。

OnActionExecuted 是在构建结果/响应之后,所以应该给你你所追求的,

在此处输入图像描述

图片来自:https ://www.c-sharpcorner.com/article/working-with-filters-in-asp-net-core-mvc/


推荐阅读