中间件破坏了 Web API 调用。

3

我有一个中间件用于记录Web API请求。以下是Startup.cs文件中的Configuration方法。如果app.UseMiddlewareapp.UseMvc之前出现,将不会调用任何Web API调用。然而,如果app.UseMiddlewareapp.UseMvc之后出现,则该中间件将不起作用(即不记录请求)。

下面提供了代码。有什么想法可以解释为什么app.UseMiddleware会影响app.UseMvc吗?

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider services)
{
    // global cors policy
    app.UseCors(x => x
        .AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader());


    app.UseHttpsRedirection();
    app.UseAuthentication();

    app.UseStaticFiles();
    app.UseSpaStaticFiles();

    app.UseMiddleware<ApiLoggingMiddleware>();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller}/{action=Index}/{id?}");
    });
}

以下是中间件:
 public async Task Invoke(HttpContext httpContext, IApiLogService apiLogService)
 {
     try
     {
         _apiLogService = apiLogService;

         var request = httpContext.Request;
         if (request.Path.StartsWithSegments(new PathString("/api")))
         {
             var stopWatch = Stopwatch.StartNew();
             var requestTime = DateTime.UtcNow;
             var requestBodyContent = await ReadRequestBody(request);
             var originalBodyStream = httpContext.Response.Body;

             await SafeLog(requestTime,
                   stopWatch.ElapsedMilliseconds,
                   200,//response.StatusCode,
                   request.Method,
                   request.Path,
                   request.QueryString.ToString(),
                   requestBodyContent
                   );           
         }
         else
         {
             await _next(httpContext);
         }
     }
     catch (Exception ex)
     {
         await _next(httpContext);
     }
 }

请问您能否分享更多中间件的代码?因为从上面的代码中,我发现缺少了RequestDelegate部分。更多信息请参见此处,同时也可以查看这里 - Mike
1
@Miky 感谢您的评论。问题已经通过将 await _next(httpContext) 放在 else 外部得到解决。 - renakre
1个回答

3

在中间件中必须始终调用await _next(httpContext);,否则请求不会沿着管道下传:

public async Task Invoke(HttpContext httpContext, IApiLogService apiLogService)
 {
     try
     {
         _apiLogService = apiLogService;

         var request = httpContext.Request;
         if (request.Path.StartsWithSegments(new PathString("/api")))
         {
             var stopWatch = Stopwatch.StartNew();
             var requestTime = DateTime.UtcNow;
             var requestBodyContent = await ReadRequestBody(request);
             var originalBodyStream = httpContext.Response.Body;

             await SafeLog(requestTime,
                   stopWatch.ElapsedMilliseconds,
                   200,//response.StatusCode,
                   request.Method,
                   request.Path,
                   request.QueryString.ToString(),
                   requestBodyContent
                   );           
         };
     }
     catch (Exception ex)
     {

     }
     await _next(httpContext);
 }

编辑(中间件简单解释):
整个中间件的工作方式是这样的 - 当请求到达您的应用程序时,它会通过中间件管道进行处理,每个中间件都必须调用下一个中间件,以便最终将请求发送到您的控制器。当您调用 await _next(httpContext); 时,实际上是在调用管道中下一个中间件的Invoke方法。如果您不调用 await _next(httpContext); ,则会停止请求,并且请求将无法传递到您的控制器。需要注意的一点是,当 await _next(httpContext); 返回时,请求已经由您的控制器服务。


谢谢你的回答。你的意思是它不应该在else里面吗? - renakre
我在我的回答中添加了有关中间件的简单说明,另外,如需更多信息,请查看微软文档 - Marmellad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接