溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

ASP.NET Core Mvc中空返回值怎么處理

發(fā)布時(shí)間:2021-08-11 10:02:06 來源:億速云 閱讀:162 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下ASP.NET Core Mvc中空返回值怎么處理,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

.NET Core MVC在如何返回操作結(jié)果方面非常靈活的。

你可以返回一個(gè)實(shí)現(xiàn)IActionResult接口的對象, 比如我們熟知的ViewResult, FileResult, ContentResult等。

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

當(dāng)然你還可以直接返回一個(gè)類的實(shí)例。

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

在.NET Core 2.1中, 你還可以返回一個(gè)ActionResult的泛型對象。

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

今天的博客中,我們將一起看一下.NET Core Mvc是如何返回一個(gè)空值對象的,以及如何改變.NET Core Mvc針對空值對象結(jié)果的默認(rèn)行為。

下面話不多說了,來一起看看詳細(xì)的介紹吧

.NET Core Mvc針對空值對象的默認(rèn)處理行為

那么當(dāng)我們在Action中返回null時(shí), 結(jié)果是什么樣的呢?

下面我們新建一個(gè)ASP.NET Core WebApi項(xiàng)目,并添加一個(gè)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; }
}

在這個(gè)Controller中,我們定義了一個(gè)圖書的集合,并提供了根據(jù)圖書ID查詢圖書的三種實(shí)現(xiàn)方式。

然后我們啟動項(xiàng)目, 并使用Postman, 并請求/api/book/3, 結(jié)果如下:

ASP.NET Core Mvc中空返回值怎么處理

你會發(fā)現(xiàn)返回的Status是204 NoContent, 而不是我們想象中的200 OK。你可修改之前代碼的注釋, 使用其他2種方式,結(jié)果也是一樣的。

你可以嘗試創(chuàng)建一個(gè)普通的ASP.NET Mvc項(xiàng)目, 添加相似的代碼,結(jié)果如下

ASP.NET Core Mvc中空返回值怎么處理

返回的結(jié)果是200 OK, 內(nèi)容是null

為什么會出現(xiàn)結(jié)果呢?

與前輩們(ASP.NET Mvc, ASP.NET WebApi)不同,ASP.NET Core Mvc非常巧妙的處理了null值,在以上的例子中,ASP.NET Core Mvc會選擇一個(gè)合適的輸出格式化器(output formatter)來輸出響應(yīng)內(nèi)容。通常這個(gè)輸出格式化器會是一個(gè)JSON格式化器或XML格式化器。

但是對于null值, ASP.NET Core Mvc使用了一種特殊的格式化器HttpNoContentOutputFormatter, 它會將null值轉(zhuǎn)換成204的狀態(tài)碼。這意味著null值不會被序列化成JSON或XML, 這可能不是我們期望的結(jié)果, 有時(shí)候我們希望返回200 OK, 響應(yīng)內(nèi)容為null。

Tips: 當(dāng)Action返回值是void或Task時(shí),ASP.NET Core Mvc默認(rèn)也會使用HttpNoContentOutputFormatter

通過修改配置移除默認(rèn)的null值格式化器

我們可以通過設(shè)置HttpNoContentOutputFormatter對象的TreatNullValueAsNoContent屬性為false,去除默認(rèn)的HttpNoContentOutputFormatter對null值的格式化。

在Startup.cs文件的ConfigureService方法中, 我們在添加Mvc服務(wù)的地方,修改默認(rèn)的輸出格式化器,代碼如下

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

修改之后我們重新運(yùn)行程序,并使用Postman訪問/api/book/3

結(jié)果如下, 返回值200 OK, 內(nèi)容為null, 這說明我們的修改成功了。

ASP.NET Core Mvc中空返回值怎么處理

使用404 Not Found代替204 No Content

在上面的例子中, 我們禁用了204 No Content行為,響應(yīng)結(jié)果變?yōu)榱?00 OK, 內(nèi)容為null。 但是有時(shí)候,我們期望當(dāng)找不到任何結(jié)果時(shí),返回404 Not Found , 那么這時(shí)候我們應(yīng)該修改代碼,進(jìn)行擴(kuò)展呢?

在.NET Core Mvc中我們可以使用自定義過濾器(Custom Filter), 來改變這一行為。

這里我們創(chuàng)建2個(gè)特性類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執(zhí)行完后觸發(fā), ResultFilterAttribute的OnResultExecuting會在action返回結(jié)果前觸發(fā)。

  • 這2個(gè)方法都是針對action的返回結(jié)果進(jìn)行了替換操作,如果返回結(jié)果的值是null, 就將其替換成NotFoundResult

添加完成后,你可以任選一個(gè)類,將他們添加在

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服務(wù)的時(shí)候配置他們

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

選擇一種重新運(yùn)行項(xiàng)目之后,效果和通過修改配置移除默認(rèn)的null值格式化器是一樣的。

IAlwaysRunResultFilter

以上的幾種解決方案看似完美無缺,但實(shí)際上還是存在一點(diǎn)瑕疵。由于ASP.NET Core Mvc中過濾器的短路機(jī)制(即在任何一個(gè)過濾器中對Result賦值都會導(dǎo)致程序跳過管道中剩余的過濾器),可能現(xiàn)在使用某些第三方組件后, 第三方組件在管道中插入自己的短路過濾器,從而導(dǎo)致我們的代碼失效。

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);
}

重新運(yùn)行程序后,使用Postman訪問/api/book/3, 程序又返回了204 Not Content, 這說明我們的代碼失效了。

這時(shí)候,為了解決這個(gè)問題,我們需要使用.NET Core 2.1中新引入的接口IAlwaysRunResultFilter。實(shí)現(xiàn)IAlwaysRunResultFilter接口的過濾器總是會執(zhí)行,不論前面的過濾器是否觸發(fā)短路。

這里我們添加一個(gè)新的過濾器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();
  }
 }
}

然后我們繼續(xù)修改BookController中的GetById方法, 為其添加NotFoundAlwaysRunFilter特性

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

重新運(yùn)行程序后,使用Postman訪問/api/book/3, 程序又成功返回了404 Not Found, 這說明我們的代碼又生效了。

以上是“ASP.NET Core Mvc中空返回值怎么處理”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI