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
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。
您可能感兴趣的文章: