本文討論ASP.NET Core 2.1中與ASP.NET Core MVC / Web API控制器中的模型綁定相關的功能。雖說這是一個功能,但從我的角度來看,它更像是一個錯誤修複! 請註意,我使用的是 NET Core 2.1 Preview 1,正式版發佈後,功能可能存在變動。 ASP.NET ...
本文討論ASP.NET Core 2.1中與ASP.NET Core MVC / Web API控制器中的模型綁定相關的功能。雖說這是一個功能,但從我的角度來看,它更像是一個錯誤修複!
請註意,我使用的是 NET Core 2.1 Preview 1,正式版發佈後,功能可能存在變動。
ASP.NET Core 2.0 模型驗證
模型驗證是ASP.NET Core MVC 管線的重要組成部分。有很多方法可以註入到驗證層(例如使用FluentValidation),最常見的方法可能是使用來自System.ComponentModel
的驗證標記來修飾綁定模型。 例如:
public class UserModel
{
[Required, EmailAddress]
public string Email { get; set; }
[Required, StringLength(1000)]
public string Name { get; set; }
}
如果您在控制器的操作方法中使用UserModel
,MvcMiddleware
則會自動創建對象的新實例,綁定模型的屬性並使用如下三個來源對其進行驗證:
- 表單 - 當使用POST將表單發送到伺服器時,發送到HTTP請求的主體中;
- 路由 - 在匹配路由後從URL段或預設值中獲取;
- 查詢字元串 - 在URL的末尾傳遞。
請註意,目前,作為JSON發送的數據預設情況下不會被綁定。如果您希望綁定請求體中的JSON數據,則需要使用此處所述的
[FromBody]
標記修飾模型。
在控制器Action方法中,可以簡單地檢查ModelState
屬性,確定提供的數據是否有效:
public class CheckoutController : Controller
{
public IActionResult SaveUser(UserModel model)
{
if(!ModelState.IsValid)
{
// Something wasn't valid on the model
return View(model);
}
// The model passed validation, do something with it
}
}
這是非常標準的MVC內容,但是如果您不想創建整個綁定模型,但仍想驗證傳入數據,該怎麼辦?
ASP.NET Core 2.0 頂級參數
DataAnnotation
標記預設MVC驗證系統使用的屬性不必應用於類的屬性,它們也可以應用於參數。這可能會導致您認為您可以完全替換UserModel
上面的示例中的以下內容:
MVC預設驗證系統使用的DataAnnotation
標記不一定應用於類的屬性,它們同樣可以應用於參數。這可能會導致您認為可以完全替換上面示例中的UserModel
,如下所示:
public class CheckoutController : Controller
{
public IActionResult SaveUser(
[Required, EmailAddress] string Email
[Required, StringLength(1000)] string Name)
{
if(!ModelState.IsValid)
{
// Something wasn't valid on the model
return View(model);
}
// The model passed validation, do something with it
}
}
不幸的是,這是行不通的!在綁定屬性時,驗證屬性將被忽略,並且ModelState.IsValid
始終是true
!
ASP.NET Core 2.1中的頂級參數
幸運的是,ASP.NET Core團隊意識到了這個問題,並且已經將修補程式合併為ASP.NET Core 2.1的一部分。因此,上一節中的代碼的行為與您所期望的一樣,參數經過驗證,並相應地進行了ModelState.IsValid
更新。
作為這項工作的一部分,您現在還可以使用[BindRequired]
標記修飾參數。當綁定非空值類型時,此標記很重要,因為使用[Required]
標記對這些屬性並不能提供預期的行為。
這意味著您現在可以執行以下操作,並確保testId
參數已從路由參數中正確綁定,並且qty
參數已從查詢字元串中綁定。在ASP.NET Core 2.1之前,它甚至不能編譯!
[HttpGet("test/{testId}")]
public IActionResult Get([BindRequired, FromRoute] Guid testId, [BindRequired, FromQuery] int qty)
{
if(!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Valid and bound
}
對於這個問題可以查閱我之前的博客:《ASP.NET Core MVC中的 [Required]與[BindRequired]》。
總結
在ASP.NET Core 2.0及以下版本中,應用於頂級參數的驗證標記將被忽略,並且ModelState
不會更新。只考慮複雜模型類型的驗證參數。
在ASP.NET Core 2.1中,驗證標記現在將在頂級參數上得到遵守。更重要的是,您可以將[BindReqired]
標記應用於參數。
ASP.NET Core 2.1 增加了很多新特性。這是一些不錯的小改進之一,它使事情變得更容易,更一致 -- 我喜歡這種改變。
翻譯自https://andrewlock.net/coming-in-asp-net-core-2-1-top-level-mvc-parameter-validation/。