视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
ASP.NET Core Mvc中空返回值的处理方法详解
2020-11-27 22:34:45 责编:小采
文档


通过修改配置移除默认的null值格式化器

我们可以通过设置HttpNoContentOutputFormatter对象的TreatNullValueAsNoContent属性为false,去除默认的HttpNoContentOutputFormatter对null值的格式化。

在Startup.cs文件的ConfigureService方法中, 我们在添加Mvc服务的地方,修改默认的输出格式化器,代码如下

public void ConfigureServices(IServiceCollection services)
{
 services.AddMvc(o =>
 {
 o.OutputFormatters.RemoveType(typeof(HttpNoContentOutputFormatter));
 o.OutputFormatters.Insert(0, new HttpNoContentOutputFormatter 
 { 
 TreatNullValueAsNoContent = false;
 });
 });
}

修改之后我们重新运行程序,并使用Postman访问/api/book/3

结果如下, 返回值200 OK, 内容为null, 这说明我们的修改成功了。

使用404 Not Found代替204 No Content

在上面的例子中, 我们禁用了204 No Content行为,响应结果变为了200 OK, 内容为null。 但是有时候,我们期望当找不到任何结果时,返回404 Not Found , 那么这时候我们应该修改代码,进行扩展呢?

在.NET Core Mvc中我们可以使用自定义过滤器(Custom Filter), 来改变这一行为。

这里我们创建2个特性类NotFoundActionFilterAttribute和NotFoundResultFilterAttribute , 代码如下:

public class NotFoundActionFilterAttribute : ActionFilterAttribute
{
 public override void OnActionExecuted(ActionExecutedContext context)
 {
 if (context.Result is ObjectResult objectResult && objectResult.Value == null)
 {
 context.Result = new NotFoundResult();
 }
 }
}

public class NotFoundResultFilterAttribute : ResultFilterAttribute
{
 public override void OnResultExecuting(ResultExecutingContext context)
 {
 if (context.Result is ObjectResult objectResult && objectResult.Value == null)
 {
 context.Result = new NotFoundResult();
 }
 }
}

代码解释

  • 这里使用了ActionFilterAttribute和ResultFilterAttribute,ActionFilterAttribute中的OnActionExecuted方法会在action执行完后触发, ResultFilterAttribute的OnResultExecuting会在action返回结果前触发。
  • 这2个方法都是针对action的返回结果进行了替换操作,如果返回结果的值是null, 就将其替换成NotFoundResult
  • 添加完成后,你可以任选一个类,将他们添加在

    controller头部

    [Route("api/[controller]")]
    [ApiController]
    [NotFoundResultFilter]
    public class BookController : ControllerBase
    {
     ...
    }

    或者action头部

    [HttpGet("{id}")]
    [NotFoundResultFilter]
    public IActionResult GetById(int id)
    {
     var item = _books.FirstOrDefault(p => p.BookId == id);
     return Ok(item);
    }

    你还可以在添加Mvc服务的时候配置他们

    public void ConfigureServices(IServiceCollection services)
    {
     services.AddMvc(o =>
     {
     o.Filters.Add(new NotFoundResultFilterAttribute());
     });
    }

    选择一种重新运行项目之后,效果和通过修改配置移除默认的null值格式化器是一样的。

    IAlwaysRunResultFilter

    以上的几种解决方案看似完美无缺,但实际上还是存在一点瑕疵。由于ASP.NET Core Mvc中过滤器的短路机制(即在任何一个过滤器中对Result赋值都会导致程序跳过管道中剩余的过滤器),可能现在使用某些第三方组件后, 第三方组件在管道中插入自己的短路过滤器,从而导致我们的代码失效。

    ASP.NET Core Mvc的过滤器,可以参见这篇文章

    下面我们添加以下的短路过滤器。

    public class ShortCircuitingFilterAttribute : ActionFilterAttribute
    {
     public override void OnActionExecuting(ActionExecutingContext context)
     {
     context.Result = new ObjectResult(null);
     }
    }

    然后修改BookController中GetById的方法

    [HttpGet("{id}")]
    [ShortCircuitingFilter]
    [NotFoundActionFilter]
    public IActionResult GetById(int id)
    {
     var item = _books.FirstOrDefault(p => p.BookId == id);
     return Ok(item);
    }

    重新运行程序后,使用Postman访问/api/book/3, 程序又返回了204 Not Content, 这说明我们的代码失效了。

    这时候,为了解决这个问题,我们需要使用.NET Core 2.1中新引入的接口IAlwaysRunResultFilter。实现IAlwaysRunResultFilter接口的过滤器总是会执行,不论前面的过滤器是否触发短路。

    这里我们添加一个新的过滤器NotFoundAlwaysRunFilterAttribute。

    public class NotFoundAlwaysRunFilterAttribute : Attribute, IAlwaysRunResultFilter
    {
     public void OnResultExecuted(ResultExecutedContext context)
     {
     }
    
     public void OnResultExecuting(ResultExecutingContext context)
     {
     if (context.Result is ObjectResult objectResult && objectResult.Value == null)
     {
     context.Result = new NotFoundResult();
     }
     }
    }

    然后我们继续修改BookController中的GetById方法, 为其添加NotFoundAlwaysRunFilter特性

    [HttpGet("{id}")]
    [ShortCircuitingFilter]
    [NotFoundActionFilter]
    [NotFoundAlwaysRunFilter]
    public IActionResult GetById(int id)
    {
     var item = _books.FirstOrDefault(p => p.BookId == id);
     return Ok(item);
    }

    重新运行程序后,使用Postman访问/api/book/3, 程序又成功返回了404 Not Found, 这说明我们的代码又生效了。

    本篇源代码: https://github.com/lamondlu/NullAction (本地下载)

    原文地址:https://www.strathweb.com/2018/10/convert-null-valued-results-to-404-in-asp-net-core-mvc/

    作者: Filip W.

    译者: Lamond Lu

    总结

    下载本文
    显示全文
    专题