日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET之模型绑定和验证

發布時間:2023/12/4 asp.net 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET之模型绑定和验证 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

介紹

模型綁定就是接收將來自HTTP請求的數據映射到模型的過程。如果找不到模型屬性的值,并不會報錯,而是給該屬性設置默認值。

示例:比如我們有一個接口為

[HttpGet("{id}")] public?ActionResult<Pet>?GetById(int?id,?bool?dogsOnly)

這個時候你的請求為:http://localhost:5000/api/pets/2?DogsOnly=true

路由系統選擇該Action后,模型綁定會執行以下的步驟:

  • 查找 GetByID 的第一個參數,該參數是一個名為 id 的整數。

  • 查找 HTTP 請求中的可用源,并在路由數據中查找 id =“2”。

  • 將字符串“2”轉換為整數 2。

  • 查找 GetByID 的下一個參數,該參數是一個名為 dogsOnly 的布爾值。

  • 查找源,并在查詢字符串中查找“DogsOnly=true”。名稱匹配不區分大小寫。

  • 將字符串“true”轉換為布爾值 true。

最后會調用GetById方法,參數Id為2,參數dogsOnly為true。

默認情況下,模型綁定以鍵值對的形式從HTTP請求中的以下源中獲取數據:

  • 表單域

  • 請求正文

  • 路由數據

  • 查詢字符串參數

  • 上傳的文件

  • 對于每個參數,按照順序掃描源。也可以直接指定源

    • [FromQuery] - 從查詢字符串獲取值。

    • [FromRoute] - 從路由數據獲取值。

    • [FromForm] - 從發布表單字段中獲取值。

    • [FromBody] - 從請求正文獲取值。

    • [FromHeader] - 從 HTTP 標頭獲取值。

    示例:

    [HttpGet] public?async?Task<User>?GetAsync([FromQuery]string?id)[HttpGet] public?async?Task<User>?GetAsync([FromRoute]string?id)[HttpGet] public?async?Task<User>?GetAsync([FromForm]string?id)[HttpPost] public?async?Task<ActionResult<string>>?AddAsync([FromBody]AddUserVm?dto)public?void?OnGet([FromHeader(Name?=?"Accept-Language")]?string?language)

    也可以編寫自定義的值提供程序,比如從cookie中獲取會話狀態,參考:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/model-binding?view=aspnetcore-5.0#additional-sources

    模型綁定

    簡單模型綁定

    例如:bool、byte、char、DateTime、DateTimeOffset、float、enum、guid、int、TimeSpan、Url、Version等

    復雜類型

    使用復雜類型必須具有要綁定的公共默認構造函數和公共可寫屬性。進行模型綁定時候,將使用公共默認構造函數來實例化類。對于復雜類型的每個屬性,模型綁定會查找名稱模式 prefix.property_name 的源。如果未找到,它將僅查找不含前綴的 properties_name。不過一般我們使用都是進行完全匹配,特殊需求才會做此操作。

    參考資料:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/model-binding?view=aspnetcore-5.0#complex-types

    內置自定義模型綁定

    通過ByteArrayModelBinder 可以實現將傳輸的base64編碼字符串轉換為字節數組。

    比如:

    ????????[HttpPost]public?void?Post([FromForm]?byte[]?file,?string?filename){var?trustedFileName?=?Path.GetRandomFileName();var?filePath?=?Path.Combine("e://",?trustedFileName);if?(System.IO.File.Exists(filePath)){return;}System.IO.File.WriteAllBytes(filePath,?file);}

    請求示例

    image.png

    接收結果

    image.png

    自定義模型綁定

    示例場景:通過請求頭傳遞后端自定義的一種token,通過自定義模型綁定將token解析后綁定到請求模型。

    參考資料:https://www.cnblogs.com/jyzhu/articles/8670536.html

    請求接口示例

    ????????[HttpGet]public?ActionResult?GetToken(TokenModel?dto){return?Ok(dto);}

    首先定義token模型類

    ????public?class?TokenModel{public?int?UserID?{?get;?set;?}public?string?UserName?{?get;?set;?}}

    自定義模型綁定器

    ????public?class?TokenModelBinder?:?IModelBinder{///?<summary>///?請求里傳遞參數token///?</summary>///?<param?name="bindingContext"></param>///?<returns></returns>public?Task?BindModelAsync(ModelBindingContext?bindingContext){//參數必須包含tokenif?(!(bindingContext.ActionContext.HttpContext.Request.Headers.ContainsKey("token")))return?Task.CompletedTask;var?token?=?bindingContext.ActionContext.HttpContext.Request.Headers["token"];//TODO??解析tokenvar?result?=?new?TokenModel(){UserID?=?111,UserName?=?"azrng",};bindingContext.Result?=?ModelBindingResult.Success(result);return?Task.CompletedTask;}}

    定義token框架綁定器

    ????public?class?TokenModelBinderProvider?:?IModelBinderProvider{public?IModelBinder?GetBinder(ModelBinderProviderContext?context){if?(context?==?null){throw?new?ArgumentNullException(nameof(context));}if?(context.Metadata.ModelType?==?typeof(TokenModel))return?new?TokenModelBinder();return?null;}}

    啟用綁定器

    ????services.AddControllers(options?=>{options.ModelBinderProviders.Insert(0,?new?TokenModelBinderProvider());});

    請求示例

    var?client?=?new?RestClient("http://localhost:5000/api/ModelVerify/GetToken"); client.Timeout?=?-1; var?request?=?new?RestRequest(Method.GET); request.AddHeader("token",?"123456"); IRestResponse?response?=?client.Execute(request); Console.WriteLine(response.Content);

    結果就是可以在GetToken方法參數獲取到我們token的值。

    模型校驗

    現在dotNetCore如果在控制器標識[ApiController],那么就會在進action前就會自動校驗模型類綁定是否符合要求,如果不符合要求自動觸發HTTP400錯誤響應。原文

    [ApiController] [Route("[controller]")] public?class?WeatherForecastController?:?ControllerBase

    驗證特性

    通過驗證特性可為屬性增加驗證規則。不僅僅有內置的驗證特性,還可以實現自定義驗證特性。

    內置驗證特性

    常用的有:必填、長度驗證、數值范圍、手機號碼、郵箱,還可以使用正則驗證

    ????public?class?AddModelVerify{[Display(Name?=?"名稱"),?Required(ErrorMessage?=?"{0}不能為空")]//?非空校驗?[MinLength(6,?ErrorMessage?=?"名稱不能小于6位")]?//?最小長度校驗[MaxLength(10,?ErrorMessage?=?"長度不超過10個")]?//?最大長度校驗public?string?UserName?{?get;?set;?}///?<summary>///?密碼///?</summary>[Display(Name?=?"密碼"),?Required(ErrorMessage?=?"{0}不能為空")][MinLength(6,?ErrorMessage?=?"密碼必須大于6位")]public?string?PassWord?{?get;?set;?}[Display(Name?=?"工號")]?//?友好名稱錯誤提示[Required(ErrorMessage?=?"{0}不能為空")][StringLength(10,?MinimumLength?=?1,?ErrorMessage?=?"{0}長度是{1}")]public?string?EmployeeNo?{?get;?set;?}}public?IActionResult?VerifyPhone([RegularExpression(@"^\d{3}-\d{3}-\d{4}$")]?string?phone)

    除了上面這些還有其他內置特性:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation?view=aspnetcore-5.0#built-in-attributes

    請求地址傳入空值,輸出結果:HTTP錯誤400

    {"errors":?{"PassWord":?["密碼不能為空","密碼必須大于6位"],"UserName":?["名稱不能為空","名稱不能小于6位"],"EmployeeNo":?["工號不能為空","工號長度是10"]},"type":?"https://tools.ietf.org/html/rfc7231#p-6.5.1","title":?"One?or?more?validation?errors?occurred.","status":?400,"traceId":?"00-d16b945b3e172a42bfe5b53d08f7487b-8d87c2ca238fdc4a-00" }

    還有一個Remote特性感覺挺有意思,使用場景是比如在ID上標注遠程特性,綁定時候自定驗證ID是否有效

    [AcceptVerbs("GET",?"POST")] public?IActionResult?VerifyID(string?id) {if?(!_userService.VerifyID(id)){return?Json($"對象未找到");}return?Json(true); }

    模型類使用指向操作方法的[Remote]特性注釋屬性

    [Remote(action:?"VerifyID",?controller:?"Users")] public?string?ID?{?get;?set;?}

    Remote其他用法:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation?view=aspnetcore-5.0#additional-fields

    自定義特性

    對于內置驗證特性無法處理的情況,我們可以創建自定義驗證特性。

    模擬場景:添加用戶時候,設置名字和工號不能一致,出生日期必須小于當前時間

    輸入模型類

    ????public?class?AddUserinfoVm{[Display(Name?=?"名稱"),?Required(ErrorMessage?=?"{0}不能為空")][MinLength(6,?ErrorMessage?=?"名稱不能小于6位")][MaxLength(10,?ErrorMessage?=?"長度不超過10個")]public?string?UserName?{?get;?set;?}///?<summary>///?密碼///?</summary>[Display(Name?=?"密碼"),?Required(ErrorMessage?=?"{0}不能為空")][MinLength(6,?ErrorMessage?=?"密碼必須大于6位")]public?string?PassWord?{?get;?set;?}[Display(Name?=?"工號")][Required(ErrorMessage?=?"{0}不能為空")][StringLength(10,?MinimumLength?=?1,?ErrorMessage?=?"{0}長度是{1}")]public?string?EmployeeNo?{?get;?set;?}///?<summary>///?出生日期///?</summary>public?DateTime?Birthday?{?get;?set;?}}

    方案一:通過添加AddUserVerifyAttribute來實現

    ????[AttributeUsage(AttributeTargets.All,?AllowMultiple?=?false)]public?class?AddUserVerifyAttribute?:?ValidationAttribute{protected?override?ValidationResult?IsValid(object?value,?ValidationContext?validationContext){var?user?=?(AddUserinfoVm)validationContext.ObjectInstance;//user?變量表示?AddUserinfoVm?對象,其中包含表單提交中的數據var?date?=?(DateTime)value;if?(date?>?DateTime.Now){return?new?ValidationResult("出生日期不能大于當前時間");}if?(user.UserName?==?user.EmployeeNo){return?new?ValidationResult("名稱和工號不能一樣");}return?ValidationResult.Success;}}

    使用方法

    ????????[AddUserVerify]public?DateTime?Birthday?{?get;?set;?}

    方案二:模型類中繼承IValidatableObject,并實現Validate方法

    ????????///?<summary>///?屬性級別的自定義驗證///?</summary>///?<param?name="validationContext"></param>///?<returns></returns>???public?IEnumerable<ValidationResult>?Validate(ValidationContext?validationContext){if?(Birthday?>?DateTime.Now){yield?return?new?ValidationResult("出生日期不能大于當前時間",?new[]?{?nameof(Birthday)?});}if?(UserName?==?EmployeeNo){yield?return?new?ValidationResult("名稱和工號不能一樣",?new[]?{?nameof(UserName),?nameof(EmployeeNo)?});}}

    請求參數:

    {"userName":?"string","passWord":?"string","employeeNo":?"string","birthday":?"2021-06-15T14:34:52.192Z" }

    輸出錯誤信息

    {"errors":?{"Birthday":?["出生日期不能大于當前時間"],"UserName":?["名稱和工號不能一樣"],"EmployeeNo":?["名稱和工號不能一樣"]},"type":?"https://tools.ietf.org/html/rfc7231#p-6.5.1","title":?"One?or?more?validation?errors?occurred.","status":?400,"traceId":?"00-18854d59f6b6fc48b5c4c6a6dbe3802c-ba23f594f351a64d-00" }

    ModelState.IsValid

    通過該方法可以實現對請求類驗證是否滿足要求并做出相應的響應。

    如果已經使用[ApiController]標識,那么該方法就不在需要。

    ????????[HttpPost]public?ActionResult?Add([FromBody]?AddModelVerify?dto){//對請求類進行驗證特性if?(ModelState.IsValid){//對請求類的值做出修改dto.UserName?=?"azrng";if?(!TryValidateModel(dto)){//重新運行驗證失敗return?Ok("修改值后驗證失敗");}return?Ok("驗證成功");}else{ModelState.AddModelError(string.Empty,?"輸入有誤");}return?Ok("");}

    禁用驗證

    ????///?<summary>///?創建不會將任何字段標記為無效的 IObjectModelValidator 實現。///?</summary>public?class?NullObjectModelValidator?:?IObjectModelValidator{public?void?Validate(ActionContext?actionContext,ValidationStateDictionary?validationState,?string?prefix,?object?model){//?該方法故意為空}}

    Startup.ConfigureServices中注入,以便替換依賴項注入容器中的默認 IObjectModelValidator 實現。

    services.AddSingleton<IObjectModelValidator,?NullObjectModelValidator>();

    統一模型攔截器

    增加ModelActionFiter過濾器

    ????public?class?ModelActionFiter?:?ActionFilterAttribute{public?override?void?OnActionExecuted(ActionExecutedContext?context){}public?override?void?OnActionExecuting(ActionExecutingContext?context){if?(!context.ModelState.IsValid){var?errorResults?=?new?List<ErrorResultDTO>();foreach?(var?item?in?context.ModelState){var?result?=?new?ErrorResultDTO{Field?=?item.Key,};foreach?(var?error?in?item.Value.Errors){if?(!string.IsNullOrEmpty(result.Message)){result.Message?+=?'|';}result.Message?+=?error.ErrorMessage;}errorResults.Add(result);}context.Result?=?new?BadRequestObjectResult(new{Code?=?StatusCodes.Status400BadRequest,Errors?=?errorResults});}}public?class?ErrorResultDTO{///?<summary>///?參數領域///?</summary>public?string?Field?{?get;?set;?}///?<summary>///?錯誤信息///?</summary>public?string?Message?{?get;?set;?}}}

    參考文檔:https://www.cnblogs.com/minskiter/p/11601873.html

    ConfigureServices中注冊過濾器并禁用默認的自動模型驗證

    ????services.AddControllers(options?=>{options.Filters.Add<ModelActionFiter>();?//注冊過濾器?}).AddNewtonsoftJson().ConfigureApiBehaviorOptions(options?=>{//[ApiController]?默認自帶有400模型驗證,且優先級比較高,如果需要自定義模型驗證,則需要先關閉默認的模型驗證options.SuppressModelStateInvalidFilter?=?true;?});

    ASP.NET Core MVC 使用 ModelStateInvalidFilter 操作篩選器來執行自定義驗證。

    輸出結果

    {"code":?400,"errors":?[{"field":?"PassWord","message":?"密碼不能為空|密碼必須大于6位"},{"field":?"UserName","message":?"名稱不能為空|名稱不能小于6位"}] }

    參考文檔

    模型綁定:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/model-binding?view=aspnetcore-5.0

    禁用綁定源推理:https://docs.microsoft.com/zh-cn/aspnet/core/web-api/?view=aspnetcore-5.0#disable-inference-rules

    禁用驗證:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/models/validation?view=aspnetcore-5.0#disable-validation

    禁用自動400響應:https://docs.microsoft.com/zh-cn/aspnet/core/web-api/?view=aspnetcore-5.0#disable-automatic-400-response

    總結

    以上是生活随笔為你收集整理的.NET之模型绑定和验证的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。