小編給大家分享一下ASP.NET Core Mvc中空返回值怎么處理,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
創(chuàng)新互聯(lián)公司主要從事網站建設、成都做網站、網頁設計、企業(yè)做網站、公司建網站等業(yè)務。立足成都服務鄰水,10年網站建設經驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:18980820575.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> 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_books = new List { 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 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, 結果如下:
你會發(fā)現返回的Status是204 NoContent, 而不是我們想象中的200 OK。你可修改之前代碼的注釋, 使用其他2種方式,結果也是一樣的。
你可以嘗試創(chuàng)建一個普通的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的狀態(tài)碼。這意味著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行為,響應結果變?yōu)榱?00 OK, 內容為null。 但是有時候,我們期望當找不到任何結果時,返回404 Not Found , 那么這時候我們應該修改代碼,進行擴展呢?
在.NET Core Mvc中我們可以使用自定義過濾器(Custom Filter), 來改變這一行為。
這里我們創(chuàng)建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執(zhí)行完后觸發(fā), ResultFilterAttribute的OnResultExecuting會在action返回結果前觸發(fā)。
這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接口的過濾器總是會執(zhí)行,不論前面的過濾器是否觸發(fā)短路。
這里我們添加一個新的過濾器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); }
重新運行程序后,使用Postman訪問/api/book/3, 程序又成功返回了404 Not Found, 這說明我們的代碼又生效了。
以上是“ASP.NET Core Mvc中空返回值怎么處理”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道!