如何从调用方法返回BadRequestObjectResult

时间:2019-04-22 13:35:06

标签: c# asp.net-core middleware

我正在开发一个API,该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响应和空白响应正文。

1 个答案:

答案 0 :(得分: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有一个非常特定的用例,用于内容协商。这意味着,当您将其设置为某些自定义内容类型时,服务器将返回具有这种内容类型的结果。出于授权目的使用它真的不适合这里。