【问题标题】:How to return BadRequestObjectResult from Invoke method如何从 Invoke 方法返回 BadRequestObjectResult
【发布时间】:2019-04-22 13:35:05
【问题描述】:

我正在开发一个 API,它最初验证来自 https 请求的 Accept 标头,然后通过中间件进行响应。我在 Invoke 方法中添加了验证 Accept 标头的逻辑,如图所示,如果验证的结果(字符串比较)为 false,我如何返回错误的请求对象。

//Invoke method 
public async Task<ObjectResult> Invoke(HttpContext context)
{
   bool result = context.Request.Headers["Accept"].ToString() == 
   "app/version.abc-ghi-api.v";
   if (result == true)
   {
     await  _next(context);   
   }
   ObjectResult objectResult = await 
   Error.GenerateErrorMessage("Accept header validation 
   failed", Log.Logger);
   return objectResult;  
}

//Error class
public class Error
{
    public async static Task<ObjectResult> Error(string message, logger log)
    {
       //logic for creating the payload
       return new BadRequestObjectResult(errorMessagePayload)
    }
}

//Startup class configure method
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
     app.UseMiddleware<AcceptHeaderMiddleware>();
     if (env.IsDevelopment())
     {   
         app.UseDeveloperExceptionPage();
     }
     else
     {          
         app.UseHsts();
     }

     app.UseMvc();
}

我期待 badObjectResult(当验证失败时)作为响应,但我得到 200 OK 响应和空白响应正文。

【问题讨论】:

    标签: c# asp.net-core middleware


    【解决方案1】:

    IActionResult 类型仅在 MVC 管道中使用。作为该管道的一部分,然后执行来自操作或 MVC 过滤器的结果对象以在 HttpResponse object 上创建实际响应。

    然而,这意味着您实际上无法在 MVC 管道之外使用操作结果对象。因此,如果您有自定义中间件,您将无法使用这些结果,因为它们不会由 MVC 管道处理(从技术上讲,您可以自己执行结果,但我不推荐这样做)。

    因此,您必须自己设置结果。如果你只是想设置一些(失败)状态码,这很容易做到:

    public async Task<ObjectResult> Invoke(HttpContext context)
    {
        bool result = context.Request.Headers["Accept"].ToString() == "app/version.abc-ghi-api.v";
        if (result)
        {
            await  _next(context);   
        }
        else
        {
            context.Result.StatusCode = 500;
        }
    }
    

    如果你想包含一个主体,那么它会变得有点复杂,因为你现在必须写入输出流,这也意味着你首先必须正确地序列化你的输出。

    因此,我建议您不要在自定义中间件中执行此操作,而是在 MVC 过滤器中执行此操作。如上所述,filters 作为 MVC 管道的一部分运行,因此它们仅与 MVC 中间件一起运行。这意味着您将无法以这种方式保护您的静态文件 - 但通常这没什么大不了的。

    在您的情况下,由于您想通过 HTTP 标头授权客户端,我建议您创建一个 authorization filter

    public class AcceptHeaderAuthorizationFilter : IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            bool result = context.HttpContext.Request.Headers["Accept"].ToString() == "app/version.abc-ghi-api.v";
            if (!result)
            {
                var result = new Error.GenerateErrorMessage("Accept header validation failed", Log.Logger);
                context.Result = result;
            }
        }
    }
    

    这现在使用 MVC 管道,因此您可以使用IActionResult 对象。由于您在授权过滤器中设置结果,因此您也在使剩余的管道短路,因此之后不会执行任何操作。执行将停止并立即产生您的结果。


    最后一点:Accept header 有一个非常具体的用例,用于内容协商。这意味着当您将其设置为某些自定义内容类型时,服务器应该返回具有这种内容类型的结果。将其用于授权目的并不适合这里。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多