音效素材网提供各类素材,打造精品素材网站!

站内导航 站长工具 投稿中心 手机访问

音效素材

ASP.NET Core Mvc中空返回值的处理方法详解
日期:2021-09-07 22:39:53   来源:脚本之家

前言

如果你是一个初学者开始学习 ASP.NET 或 ASP.NET MVC, 你可能并不知道什么是. net Framework和. net ore。不用担心!我建议您看下官方文档https://docs.microsoft.com/zh-cn/aspnet/index , 您可以轻松地看到比较和差异。

.NET Core MVC在如何返回操作结果方面非常灵活的。

你可以返回一个实现IActionResult接口的对象, 比如我们熟知的ViewResult, FileResult, ContentResult等。

[HttpGet]
public IActionResult SayGood()
{
 return Content("Good!");
}

当然你还可以直接返回一个类的实例。

[HttpGet]
public string HelloWorld()
{
 return "Hello World";
}

在.NET Core 2.1中, 你还可以返回一个ActionResult的泛型对象。

[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
 return new string[] { "value1", "value2" };
}

今天的博客中,我们将一起看一下.NET Core Mvc是如何返回一个空值对象的,以及如何改变.NET Core Mvc针对空值对象结果的默认行为。

下面话不多说了,来一起看看详细的介绍吧

.NET Core Mvc针对空值对象的默认处理行为

那么当我们在Action中返回null时, 结果是什么样的呢?

下面我们新建一个ASP.NET Core WebApi项目,并添加一个BookController, 其代码如下:

[Route("api/[controller]")]
[ApiController]
public class BookController : ControllerBase
{
 private readonly List<Book> _books = new List<Book> {
  new Book(1, "CLR via C#"),
  new Book(2, ".NET Core Programming")
 };

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

 //[HttpGet("{id}")]
 //public ActionResult<Book> GetById(int id)
 //{
 // var book = _books.FirstOrDefault(p => p.BookId == id);
 // return book;
 //}

 //[HttpGet("{id}")]
 //public Book GetById(int id)
 //{
 // var book = _books.FirstOrDefault(p => p.BookId == id);
 // return book;
 //}
}

public class Book
{
 public Book(int bookId, string bookName)
 {
  BookId = bookId;
  BookName = bookName;
 }

 public int BookId { get; set; }

 public string BookName { get; set; }
}

在这个Controller中,我们定义了一个图书的集合,并提供了根据图书ID查询图书的三种实现方式。

然后我们启动项目, 并使用Postman, 并请求/api/book/3, 结果如下:

你会发现返回的Status是204 NoContent, 而不是我们想象中的200 OK。你可修改之前代码的注释, 使用其他2种方式,结果也是一样的。

你可以尝试创建一个普通的ASP.NET Mvc项目, 添加相似的代码,结果如下


返回的结果是200 OK, 内容是null

为什么会出现结果呢?

与前辈们(ASP.NET Mvc, ASP.NET WebApi)不同,ASP.NET Core Mvc非常巧妙的处理了null值,在以上的例子中,ASP.NET Core Mvc会选择一个合适的输出格式化器(output formatter)来输出响应内容。通常这个输出格式化器会是一个JSON格式化器或XML格式化器。

但是对于null值, ASP.NET Core Mvc使用了一种特殊的格式化器HttpNoContentOutputFormatter, 它会将null值转换成204的状态码。这意味着null值不会被序列化成JSON或XML, 这可能不是我们期望的结果, 有时候我们希望返回200 OK, 响应内容为null。

Tips: 当Action返回值是void或Task时,ASP.NET Core Mvc默认也会使用HttpNoContentOutputFormatter

通过修改配置移除默认的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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

    您感兴趣的教程

    在docker中安装mysql详解

    本篇文章主要介绍了在docker中安装mysql详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编...

    详解 安装 docker mysql

    win10中文输入法仅在桌面显示怎么办?

    win10中文输入法仅在桌面显示怎么办?

    win10系统使用搜狗,QQ输入法只有在显示桌面的时候才出来,在使用其他程序输入框里面却只能输入字母数字,win10中...

    win10 中文输入法

    一分钟掌握linux系统目录结构

    这篇文章主要介绍了linux系统目录结构,通过结构图和多张表格了解linux系统目录结构,感兴趣的小伙伴们可以参考一...

    结构 目录 系统 linux

    PHP程序员玩转Linux系列 Linux和Windows安装

    这篇文章主要为大家详细介绍了PHP程序员玩转Linux系列文章,Linux和Windows安装nginx教程,具有一定的参考价值,感兴趣...

    玩转 程序员 安装 系列 PHP

    win10怎么安装杜比音效Doby V4.1 win10安装杜

    第四代杜比®家庭影院®技术包含了一整套协同工作的技术,让PC 发出清晰的环绕声同时第四代杜比家庭影院技术...

    win10杜比音效

    纯CSS实现iOS风格打开关闭选择框功能

    这篇文章主要介绍了纯CSS实现iOS风格打开关闭选择框,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作...

    css ios c

    Win7如何给C盘扩容 Win7系统电脑C盘扩容的办法

    Win7如何给C盘扩容 Win7系统电脑C盘扩容的

    Win7给电脑C盘扩容的办法大家知道吗?当系统分区C盘空间不足时,就需要给它扩容了,如果不管,C盘没有足够的空间...

    Win7 C盘 扩容

    百度推广竞品词的投放策略

    SEM是基于关键词搜索的营销活动。作为推广人员,我们所做的工作,就是打理成千上万的关键词,关注它们的质量度...

    百度推广 竞品词

    Visual Studio Code(vscode) git的使用教程

    这篇文章主要介绍了详解Visual Studio Code(vscode) git的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...

    教程 Studio Visual Code git

    七牛云储存创始人分享七牛的创立故事与

    这篇文章主要介绍了七牛云储存创始人分享七牛的创立故事与对Go语言的应用,七牛选用Go语言这门新兴的编程语言进行...

    七牛 Go语言

    Win10预览版Mobile 10547即将发布 9月19日上午

    微软副总裁Gabriel Aul的Twitter透露了 Win10 Mobile预览版10536即将发布,他表示该版本已进入内部慢速版阶段,发布时间目...

    Win10 预览版

    HTML标签meta总结,HTML5 head meta 属性整理

    移动前端开发中添加一些webkit专属的HTML5头部标签,帮助浏览器更好解析HTML代码,更好地将移动web前端页面表现出来...

    移动端html5模拟长按事件的实现方法

    这篇文章主要介绍了移动端html5模拟长按事件的实现方法的相关资料,小编觉得挺不错的,现在分享给大家,也给大家...

    移动端 html5 长按

    HTML常用meta大全(推荐)

    这篇文章主要介绍了HTML常用meta大全(推荐),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参...

    cdr怎么把图片转换成位图? cdr图片转换为位图的教程

    cdr怎么把图片转换成位图? cdr图片转换为

    cdr怎么把图片转换成位图?cdr中插入的图片想要转换成位图,该怎么转换呢?下面我们就来看看cdr图片转换为位图的...

    cdr 图片 位图

    win10系统怎么录屏?win10系统自带录屏详细教程

    win10系统怎么录屏?win10系统自带录屏详细

    当我们是使用win10系统的时候,想要录制电脑上的画面,这时候有人会想到下个第三方软件,其实可以用电脑上的自带...

    win10 系统自带录屏 详细教程

    + 更多教程 +
    ASP编程JSP编程PHP编程.NET编程python编程