ASP.NET Core Mvc中空返回值的處理方法詳解

 更新時間:2018年10月19日 16:39:25   作者:Lamond Lu   我要評論

這篇文章主要給大家介紹了關于ASP.NET Core Mvc中空返回值的處理方法,文中通過示例代碼介紹的非常詳細,對大家學習或者使用ASP.NET Core Mvc具有一定的參考學習價值,需要的朋友們下面來一起看看吧

前言

如果你是一個初學者開始學習 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

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

最新評論

时时彩包赢公式0369