.NET Core第29天_Model验证配置准备流程_各种验证资料注解使用方式

新建一个.net core mvc专案後

预设每一个检视之所以都能套用版面配置页
主要是在於藉由.\Views_ViewStart.cshtml进行的全域预设版面配置设置
https://ithelp.ithome.com.tw/upload/images/20210930/20107452N5PgQhdAak.png
而预设专案微软验证脚本采用的是
.\Views\Shared_ValidationScriptsPartial.cshtml当中的jquery两个脚本

<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

进行client验证机制。

预设版面配置页.\Views\Shared_Layout.cshtml,而针对脚本引入是没有特别去添加,因此需再各自检视中做引入。

@await RenderSectionAsync("Scripts", required: false)

在版面配置页面中,以非同步方式转译名为之区段的内容

	
public System.Threading.Tasks.Task<Microsoft.AspNetCore.Html.HtmlString> RenderSectionAsync (string name, bool required);

参数
name (String)
要呈现的区段。

required(Boolean)
指出 name 必须使用页面中的) (注册区段 @section 。

https://ithelp.ithome.com.tw/upload/images/20210930/20107452tQXRX7MI1q.png

新增一控制器名ValidDemoController.cs跟相应Index检视
Index检视中去进行非同步引入验证脚本隶属的部分检视

@section scripts{
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

在ViewModel中要进行验证相关的资料注解使用时
必须引用using System.ComponentModel.DataAnnotations;
各项注解用中括号包覆

预设各个衍生的验证资料注解都是继承自ValidationAttribute

#region 组件 System.ComponentModel.Annotations, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\5.0.0\ref\net5.0\System.ComponentModel.Annotations.dll
#endregion

#nullable enable


namespace System.ComponentModel.DataAnnotations
{
    //
    // 摘要:
    //     Serves as the base class for all validation attributes.
    public abstract class ValidationAttribute : Attribute
    {
        //
        // 摘要:
        //     Initializes a new instance of the System.ComponentModel.DataAnnotations.ValidationAttribute
        //     class.
        protected ValidationAttribute();
        //
        // 摘要:
        //     Initializes a new instance of the System.ComponentModel.DataAnnotations.ValidationAttribute
        //     class by using the function that enables access to validation resources.
        //
        // 参数:
        //   errorMessageAccessor:
        //     The function that enables access to validation resources.
        //
        // 例外状况:
        //   T:System.ArgumentNullException:
        //     errorMessageAccessor is null.
        protected ValidationAttribute(Func<string> errorMessageAccessor);
        //
        // 摘要:
        //     Initializes a new instance of the System.ComponentModel.DataAnnotations.ValidationAttribute
        //     class by using the error message to associate with a validation control.
        //
        // 参数:
        //   errorMessage:
        //     The error message to associate with a validation control.
        protected ValidationAttribute(string errorMessage);

        //
        // 摘要:
        //     Gets or sets an error message to associate with a validation control if validation
        //     fails.
        //
        // 传回:
        //     The error message that is associated with the validation control.
        public string? ErrorMessage { get; set; }
        //
        // 摘要:
        //     Gets or sets the error message resource name to use in order to look up the System.ComponentModel.DataAnnotations.ValidationAttribute.ErrorMessageResourceType
        //     property value if validation fails.
        //
        // 传回:
        //     The error message resource that is associated with a validation control.
        public string? ErrorMessageResourceName { get; set; }
        //
        // 摘要:
        //     Gets or sets the resource type to use for error-message lookup if validation
        //     fails.
        //
        // 传回:
        //     The type of error message that is associated with a validation control.
        public Type? ErrorMessageResourceType { get; set; }
        //
        // 摘要:
        //     Gets a value that indicates whether the attribute requires validation context.
        //
        // 传回:
        //     true if the attribute requires validation context; otherwise, false.
        public virtual bool RequiresValidationContext { get; }
        //
        // 摘要:
        //     Gets the localized validation error message.
        //
        // 传回:
        //     The localized validation error message.
        protected string ErrorMessageString { get; }

        //
        // 摘要:
        //     Applies formatting to an error message, based on the data field where the error
        //     occurred.
        //
        // 参数:
        //   name:
        //     The name to include in the formatted message.
        //
        // 传回:
        //     An instance of the formatted error message.
        //
        // 例外状况:
        //   T:System.InvalidOperationException:
        //     The current attribute is malformed.
        public virtual string FormatErrorMessage(string name);
        //
        // 摘要:
        //     Checks whether the specified value is valid with respect to the current validation
        //     attribute.
        //
        // 参数:
        //   value:
        //     The value to validate.
        //
        //   validationContext:
        //     The context information about the validation operation.
        //
        // 传回:
        //     An instance of the System.ComponentModel.DataAnnotations.ValidationResult class.
        //
        // 例外状况:
        //   T:System.InvalidOperationException:
        //     The current attribute is malformed.
        //
        //   T:System.ArgumentNullException:
        //     validationContext is null.
        //
        //   T:System.NotImplementedException:
        //     System.ComponentModel.DataAnnotations.ValidationAttribute.IsValid(System.Object,System.ComponentModel.DataAnnotations.ValidationContext)
        //     has not been implemented by a derived class.
        public ValidationResult? GetValidationResult(object? value, ValidationContext validationContext);
        //
        // 摘要:
        //     Determines whether the specified value of the object is valid.
        //
        // 参数:
        //   value:
        //     The value of the object to validate.
        //
        // 传回:
        //     true if the specified value is valid; otherwise, false.
        //
        // 例外状况:
        //   T:System.InvalidOperationException:
        //     The current attribute is malformed.
        //
        //   T:System.NotImplementedException:
        //     Neither overload of IsValid has been implemented by a derived class.
        public virtual bool IsValid(object? value);
        //
        // 摘要:
        //     Validates the specified object.
        //
        // 参数:
        //   value:
        //     The object to validate.
        //
        //   validationContext:
        //     The System.ComponentModel.DataAnnotations.ValidationContext object that describes
        //     the context where the validation checks are performed. This parameter cannot
        //     be null.
        //
        // 例外状况:
        //   T:System.ComponentModel.DataAnnotations.ValidationException:
        //     Validation failed.
        //
        //   T:System.InvalidOperationException:
        //     The current attribute is malformed.
        //
        //   T:System.NotImplementedException:
        //     System.ComponentModel.DataAnnotations.ValidationAttribute.IsValid(System.Object,System.ComponentModel.DataAnnotations.ValidationContext)
        //     has not been implemented by a derived class.
        public void Validate(object? value, ValidationContext validationContext);
        //
        // 摘要:
        //     Validates the specified object.
        //
        // 参数:
        //   value:
        //     The value of the object to validate.
        //
        //   name:
        //     The name to include in the error message.
        //
        // 例外状况:
        //   T:System.ComponentModel.DataAnnotations.ValidationException:
        //     value is not valid.
        //
        //   T:System.InvalidOperationException:
        //     The current attribute is malformed.
        public void Validate(object? value, string name);
        //
        // 摘要:
        //     Validates the specified value with respect to the current validation attribute.
        //
        // 参数:
        //   value:
        //     The value to validate.
        //
        //   validationContext:
        //     The context information about the validation operation.
        //
        // 传回:
        //     An instance of the System.ComponentModel.DataAnnotations.ValidationResult class.
        //
        // 例外状况:
        //   T:System.InvalidOperationException:
        //     The current attribute is malformed.
        //
        //   T:System.NotImplementedException:
        //     System.ComponentModel.DataAnnotations.ValidationAttribute.IsValid(System.Object,System.ComponentModel.DataAnnotations.ValidationContext)
        //     has not been implemented by a derived class.
        protected virtual ValidationResult? IsValid(object? value, ValidationContext validationContext);
    }
}

Required

RequiredAttribute.cs

#region 组件 System.ComponentModel.Annotations, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\5.0.0\ref\net5.0\System.ComponentModel.Annotations.dll
#endregion

#nullable enable


namespace System.ComponentModel.DataAnnotations
{
    //
    // 摘要:
    //     Specifies that a data field value is required.
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
    public class RequiredAttribute : ValidationAttribute
    {
        //
        // 摘要:
        //     Initializes a new instance of the System.ComponentModel.DataAnnotations.RequiredAttribute
        //     class.
        public RequiredAttribute();

        //
        // 摘要:
        //     Gets or sets a value that indicates whether an empty string is allowed.
        //
        // 传回:
        //     true if an empty string is allowed; otherwise, false. The default value is false.
        public bool AllowEmptyStrings { get; set; }

        //
        // 摘要:
        //     Checks that the value of the required data field is not empty.
        //
        // 参数:
        //   value:
        //     The data field value to validate.
        //
        // 传回:
        //     true if validation is successful; otherwise, false.
        //
        // 例外状况:
        //   T:System.ComponentModel.DataAnnotations.ValidationException:
        //     The data field value was null.
        public override bool IsValid(object? value);
    }
}

Required中还可以特别去设置
AllowEmptyStrings的特性,该特性只有在Server-Side下才有作用。
代表是否远许一个空字串""(双引号包覆的空字串),空null。
在进行模型物件绑定输入框时,我们在输入框输入的空字串会被自动转为null因此AllowEmptyStrings=true会没有效果,不会去验证是否为空字串("")。
需要额外配置另一个特性DisplayFormat,去禁止将空字串("")转为null,也就是ConvertEmptyStringToNull属性设置为false。

新建好一个RequeredController.cs

using DotNet5App7.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Controllers
{
    public class RequiredController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public IActionResult Index(RequiredViewModel model)
        {

            return View(model);
        }
    }
}

RequiredViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace DotNet5App7.Models
{
    public class RequiredViewModel
    {
        [Display(Name="姓名")]
        [Required(AllowEmptyStrings = true, ErrorMessage = "{0}不可为空!")]
        [DisplayFormat(ConvertEmptyStringToNull = false)]
        public string Name { get; set; }
        [Display(Name ="年龄")]
        [Required(ErrorMessage ="{0}不可为空!")]
        public int Age { get; set; }
    }
}

./Views/Required/Index.cshtml

@{
    ViewData["Title"] = "非空验证";
}

@model RequiredViewModel
<form method="post">
    <div>
        <label asp-for="Name"></label>
        <input type="text" asp-for="Name" />
        <span asp-validation-for="Name"></span>
    </div>
    <div>
        <label asp-for="Age"></label>
        <input type="text" asp-for="Age" />
        <span asp-validation-for="Age"></span>
    </div>
    <div>
        <input type="submit" value="提交" />
    </div>
</form>


@section scripts{
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

原先设置运行效果
https://ithelp.ithome.com.tw/upload/images/20210930/20107452J3AS4pKzIk.png

调整之後
https://ithelp.ithome.com.tw/upload/images/20210930/20107452l3XSXGLuGX.png

**StringLength **
主要可以设置最小跟最大字元长度,若只设定一个参数时代表最大长度。
长度是以字元个数来算,一个中文字跟英文字母都算一个字元。
相关的属性还有MaxLength跟MinLength,当同时有使用到MaxLength跟MinLength属性时,也相当於使用StringLength属性。

MaxLength
指定最大允许输入字元数

MinLength
指定最少输入字元数

LengthViewModel.cs范本

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class LengthViewModel
    {
        [Display(Name = "用户名")]
        //[MinLength(6, ErrorMessage = "{0}最小字元数是{1}。")]
        //[MaxLength(10,ErrorMessage ="{0}最大字字元是{1}。")]
        [StringLength(10, MinimumLength = 6, ErrorMessage = "{0}的最小字元数是{2},最大字元数是{1}。")]
        [Required(ErrorMessage = "{0}不可为空。")]
        public string UserName { get; set; }
    }
}

LengthController.cs

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Controllers
{
    public class LengthController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }
}

./Views/Length/Index.cshtml

@{
    ViewData["Title"] = "字元长度验证";
}
@model LengthViewModel

<form method="post">
    <div>
        <label asp-for="UserName"></label>
        <input type="text" asp-for="UserName" />
        <span asp-validation-for="UserName"></span>
    </div>
    <div>
        <input type="submit" value="提交" />
    </div>
</form>
@section scripts{
    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

运行效果
https://ithelp.ithome.com.tw/upload/images/20210930/20107452aFnjvqywu1.png

RegularExpression

正规表示式匹配验证,比方email 、电话、年龄。
RegularExpressionAttribute.cs

#region 组件 System.ComponentModel.Annotations, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\5.0.0\ref\net5.0\System.ComponentModel.Annotations.dll
#endregion

#nullable enable


namespace System.ComponentModel.DataAnnotations
{
    //
    // 摘要:
    //     Specifies that a data field value in ASP.NET Dynamic Data must match the specified
    //     regular expression.
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
    public class RegularExpressionAttribute : ValidationAttribute
    {
        //
        // 摘要:
        //     Initializes a new instance of the System.ComponentModel.DataAnnotations.RegularExpressionAttribute
        //     class.
        //
        // 参数:
        //   pattern:
        //     The regular expression that is used to validate the data field value.
        //
        // 例外状况:
        //   T:System.ArgumentNullException:
        //     pattern is null.
        public RegularExpressionAttribute(string pattern);

        //
        // 摘要:
        //     Gets or sets the amount of time in milliseconds to execute a single matching
        //     operation before the operation times out.
        //
        // 传回:
        //     The amount of time in milliseconds to execute a single matching operation.
        public int MatchTimeoutInMilliseconds { get; set; }
        //
        // 摘要:
        //     Gets the regular expression pattern.
        //
        // 传回:
        //     The pattern to match.
        public string Pattern { get; }

        //
        // 摘要:
        //     Formats the error message to display if the regular expression validation fails.
        //
        // 参数:
        //   name:
        //     The name of the field that caused the validation failure.
        //
        // 传回:
        //     The formatted error message.
        //
        // 例外状况:
        //   T:System.InvalidOperationException:
        //     The current attribute is ill-formed.
        //
        //   T:System.ArgumentException:
        //     The System.ComponentModel.DataAnnotations.RegularExpressionAttribute.Pattern
        //     is not a valid regular expression.
        public override string FormatErrorMessage(string name);
        //
        // 摘要:
        //     Checks whether the value entered by the user matches the regular expression pattern.
        //
        // 参数:
        //   value:
        //     The data field value to validate.
        //
        // 传回:
        //     true if validation is successful; otherwise, false.
        //
        // 例外状况:
        //   T:System.ComponentModel.DataAnnotations.ValidationException:
        //     The data field value did not match the regular expression pattern.
        //
        //   T:System.InvalidOperationException:
        //     The current attribute is ill-formed.
        //
        //   T:System.ArgumentException:
        //     System.ComponentModel.DataAnnotations.RegularExpressionAttribute.Pattern is not
        //     a valid regular expression.
        public override bool IsValid(object? value);
    }
}

新建控制器和相应检视
RegularController.cs 就用预设回传Index,不动

./Views/Regular/Index.cshtml

@{
    ViewData["Title"] = "正规表示式匹配验证";
}
@model RegularViewModel
<form>
    <div>
        <label asp-for="Age"></label>
        <input type="text" asp-for="Age" />
        <span asp-validation-for="Age"></span>
    </div>
    <div>
        <input type="submit" value="提交" />
    </div>
</form>
@section scripts{
    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

RegularViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class RegularViewModel
    {
        [Display(Name = "年龄")]
        [RegularExpression("[1-9][0-9]", ErrorMessage = "{0}限定输入两位数字,开头不可用0。")]
        public int Age { get; set; }
    }
}

运行效果

https://ithelp.ithome.com.tw/upload/images/20210930/20107452O19vuw8bAm.png

Range

Range属性接受int , double的参数,可用於验证是否坐落特定数值范围。
该属性中可以用Type资料型态作为参数,用於接收传入参数为string的可用typeof()来进行型态转换。Range属性中最小值和最大值,也是包括在范围内的。

RangeAttribute.cs

#region 组件 System.ComponentModel.Annotations, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\5.0.0\ref\net5.0\System.ComponentModel.Annotations.dll
#endregion

#nullable enable


namespace System.ComponentModel.DataAnnotations
{
    //
    // 摘要:
    //     Specifies the numeric range constraints for the value of a data field.
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
    public class RangeAttribute : ValidationAttribute
    {
        //
        // 摘要:
        //     Initializes a new instance of the System.ComponentModel.DataAnnotations.RangeAttribute
        //     class by using the specified minimum and maximum values.
        //
        // 参数:
        //   minimum:
        //     Specifies the minimum value allowed for the data field value.
        //
        //   maximum:
        //     Specifies the maximum value allowed for the data field value.
        public RangeAttribute(double minimum, double maximum);
        //
        // 摘要:
        //     Initializes a new instance of the System.ComponentModel.DataAnnotations.RangeAttribute
        //     class by using the specified minimum and maximum values.
        //
        // 参数:
        //   minimum:
        //     Specifies the minimum value allowed for the data field value.
        //
        //   maximum:
        //     Specifies the maximum value allowed for the data field value.
        public RangeAttribute(int minimum, int maximum);
        //
        // 摘要:
        //     Initializes a new instance of the System.ComponentModel.DataAnnotations.RangeAttribute
        //     class by using the specified minimum and maximum values and the specific type.
        //
        // 参数:
        //   type:
        //     Specifies the type of the object to test.
        //
        //   minimum:
        //     Specifies the minimum value allowed for the data field value.
        //
        //   maximum:
        //     Specifies the maximum value allowed for the data field value.
        //
        // 例外状况:
        //   T:System.ArgumentNullException:
        //     type is null.
        public RangeAttribute(Type type, string minimum, string maximum);

        //
        // 摘要:
        //     Gets or sets a value that determines whether any conversions of the value being
        //     validated to System.ComponentModel.DataAnnotations.RangeAttribute.OperandType
        //     as set by the type parameter of the System.ComponentModel.DataAnnotations.RangeAttribute.#ctor(System.Type,System.String,System.String)
        //     constructor use the invariant culture or the current culture.
        //
        // 传回:
        //     true to use the invariant culture for any conversions; false to use the culture
        //     that is current at the time of the validation.
        public bool ConvertValueInInvariantCulture { get; set; }
        //
        // 摘要:
        //     Gets the maximum allowed field value.
        //
        // 传回:
        //     The maximum value that is allowed for the data field.
        public object Maximum { get; }
        //
        // 摘要:
        //     Gets the minimum allowed field value.
        //
        // 传回:
        //     The minimum value that is allowed for the data field.
        public object Minimum { get; }
        //
        // 摘要:
        //     Gets the type of the data field whose value must be validated.
        //
        // 传回:
        //     The type of the data field whose value must be validated.
        public Type OperandType { get; }
        //
        // 摘要:
        //     Gets or sets a value that determines whether string values for System.ComponentModel.DataAnnotations.RangeAttribute.Minimum
        //     and System.ComponentModel.DataAnnotations.RangeAttribute.Maximum are parsed using
        //     the invariant culture rather than the current culture.
        public bool ParseLimitsInInvariantCulture { get; set; }

        //
        // 摘要:
        //     Formats the error message that is displayed when range validation fails.
        //
        // 参数:
        //   name:
        //     The name of the field that caused the validation failure.
        //
        // 传回:
        //     The formatted error message.
        //
        // 例外状况:
        //   T:System.InvalidOperationException:
        //     The current attribute is ill-formed.
        public override string FormatErrorMessage(string name);
        //
        // 摘要:
        //     Checks that the value of the data field is in the specified range.
        //
        // 参数:
        //   value:
        //     The data field value to validate.
        //
        // 传回:
        //     true if the specified value is in the range; otherwise, false.
        //
        // 例外状况:
        //   T:System.ComponentModel.DataAnnotations.ValidationException:
        //     The data field value was outside the allowed range.
        //
        //   T:System.InvalidOperationException:
        //     The current attribute is ill-formed.
        public override bool IsValid(object? value);
    }
}

新建好RangeController.cs跟相应Index检视

Index.cshtml

@{
    ViewData["Title"] = "范围验证";
}
@model RangeViewModel
<form>
    <div>
        <label asp-for="Price"></label>
        <input type="text" asp-for="Price" />
        <span asp-validation-for="Price"></span>
    </div>
    <div>
        <input type="submit" value="提交" />
    </div>
</form>

@section scripts{
    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

RangeViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class RangeViewModel
    {
        [Display(Name = "价格")]
        //[Range(10.1,30.5,ErrorMessage ="{0}范围是{1}-{2}。")]
        [Range(typeof(string), "10.1", "30.5", ErrorMessage = "{0}范围是{1}-{2}。")]
        public double Price { get; set; }
    }
}

运行效果

https://ithelp.ithome.com.tw/upload/images/20210930/20107452aIWjKNNEkt.png

Compare

两次输入是否一致的验证
比方密码、验证密码

新建好CompareController.cs跟相应Index检视

Index.cshtml
(这里密码暂时用明码显示方式便於查看)

@{
    ViewData["Title"] = "比较验证";
}
@model CompareViewModel
<form>
    <div>
        <label asp-for="Password"></label>
        <input type="text" asp-for="Password" />
        <span asp-validation-for="Password"></span>
    </div>
    <div>
        <label asp-for="ConfirmPassword"></label>
        <input type="text" asp-for="ConfirmPassword" />
        <span asp-validation-for="ConfirmPassword"></span>
    </div>
    <div>
        <input type="submit" value="提交" />
    </div>
</form>
@section scripts{
    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

CompareViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class CompareViewModel
    {
        [Display(Name = "密码")]
        [Required]
        public string Password { get; set; }

        [Display(Name = "确认密码")]
        [Compare("Password", ErrorMessage = "{0}和密码不一致。")]
        [Required]
        public string ConfirmPassword { get; set; }
    }
}

运行效果
https://ithelp.ithome.com.tw/upload/images/20210930/20107452h9Hakj7Cr9.png

Remote

可用来实践利用Server-Side的 call back函数执行client-side验证。
用法[Remote("动作方法名","隶属控制器名")],其隶属於Microsoft.AspNetCore.Mvc该命名空间。

RemoteAttribute.cs

#region 组件 Microsoft.AspNetCore.Mvc.ViewFeatures, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// C:\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\5.0.0\ref\net5.0\Microsoft.AspNetCore.Mvc.ViewFeatures.dll
#endregion

using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System;

namespace Microsoft.AspNetCore.Mvc
{
    //
    // 摘要:
    //     A Microsoft.AspNetCore.Mvc.RemoteAttributeBase for controllers which configures
    //     Unobtrusive validation to send an Ajax request to the web site. The invoked action
    //     should return JSON indicating whether the value is valid.
    //
    // 备注:
    //     Does no server-side validation of the final form submission.
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
    public class RemoteAttribute : RemoteAttributeBase
    {
        //
        // 摘要:
        //     Initializes a new instance of the Microsoft.AspNetCore.Mvc.RemoteAttribute class.
        //
        // 参数:
        //   routeName:
        //     The route name used when generating the URL where client should send a validation
        //     request.
        //
        // 备注:
        //     Finds the routeName in any area of the application.
        public RemoteAttribute(string routeName);
        //
        // 摘要:
        //     Initializes a new instance of the Microsoft.AspNetCore.Mvc.RemoteAttribute class.
        //
        // 参数:
        //   action:
        //     The action name used when generating the URL where client should send a validation
        //     request.
        //
        //   controller:
        //     The controller name used when generating the URL where client should send a validation
        //     request.
        //
        // 备注:
        //     If either action or controller is null, uses the corresponding ambient value.
        //     Finds the controller in the current area.
        public RemoteAttribute(string action, string controller);
        //
        // 摘要:
        //     Initializes a new instance of the Microsoft.AspNetCore.Mvc.RemoteAttribute class.
        //
        // 参数:
        //   action:
        //     The action name used when generating the URL where client should send a validation
        //     request.
        //
        //   controller:
        //     The controller name used when generating the URL where client should send a validation
        //     request.
        //
        //   areaName:
        //     The name of the area containing the controller.
        //
        // 备注:
        //     If either action or controller is null, uses the corresponding ambient value.
        //     If areaName is null, finds the controller in the root area. Use the Microsoft.AspNetCore.Mvc.RemoteAttribute.#ctor(System.String,System.String)
        //     overload find the controller in the current area. Or explicitly pass the current
        //     area's name as the areaName argument to this overload.
        public RemoteAttribute(string action, string controller, string areaName);
        //
        // 摘要:
        //     Initializes a new instance of the Microsoft.AspNetCore.Mvc.RemoteAttribute class.
        //
        // 备注:
        //     Intended for subclasses that support URL generation with no route, action, or
        //     controller names.
        protected RemoteAttribute();

        //
        // 摘要:
        //     Gets or sets the route name used when generating the URL where client should
        //     send a validation request.
        protected string RouteName { get; set; }

        protected override string GetUrl(ClientModelValidationContext context);
    }
}

新建好RemoteController跟相应Index检视

RemoteController.cs

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Controllers
{
    public class RemoteController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// Call Back Function for Remote Validation
        /// </summary>
        /// <param name="name"></param>
        /// <param name="age"></param>
        /// <returns></returns>
        public JsonResult CheckName(string name)
        {
            bool b = false;
            if (name.Equals("Andy"))
            {
                b = true;
            }
            return Json(b);
        }
    }
}

Index.cshtml

@{
    ViewData["Title"] = "Remote验证";
}
@model RemoteViewModel
<form>
    <div>
        <label asp-for="Name"></label>
        <input type="text" asp-for="Name" />
        <span asp-validation-for="Name"></span>
    </div>
    <div>
        <label asp-for="Age"></label>
        <input type="text" asp-for="Age" />
        <span asp-validation-for="Age"></span>
    </div>
    <div>
        <input type="submit" value="提交" />
    </div>
</form>

@section scripts{
    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

RemoteViewModel.cs

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class RemoteViewModel
    {
        [Display(Name = "姓名")]
        [Remote("CheckName", "Remote")]
        public string Name { get; set; }

        [Display(Name = "年龄")]
        public int Age { get; set; }
    }
}

这里可以观察运行结果
当输入一个随意的名称时会自动到server-side我们指定的call back函数做验证
https://ithelp.ithome.com.tw/upload/images/20210930/20107452Ylc1rK4pdp.png

当改为Andy时才消失警示(这里判断是大小写有差)
https://ithelp.ithome.com.tw/upload/images/20210930/20107452RVy4JZ4Rm7.png

AdditionalFields属性於Remote下可以在多透过设置它来附加额外要验证的参数栏位。
使call back函数可以传进更多参数

微调後的RemoteViewModel.cs

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class RemoteViewModel
    {
        [Display(Name = "姓名")]
        [Remote("CheckName", "Remote", AdditionalFields = "Age", HttpMethod = "GET", ErrorMessage = "请输入正确的内容。")]
        public string Name { get; set; }

        [Display(Name = "年龄")]
        public int Age { get; set; }
    }
}

这里还可以透过HttpMethod设置要采用POST或GET(默认)
AdditionalFields 当有多个参数则可用逗号分隔。

https://ithelp.ithome.com.tw/upload/images/20210930/20107452JexucVG3z8.png

微调後的RemoteController.cs

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Controllers
{
    public class RemoteController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        /// <summary>
        /// Call Back Function for Remote Validation
        /// </summary>
        /// <param name="name"></param>
        /// <param name="age"></param>
        /// <returns></returns>
        public JsonResult CheckName(string name,int age)
        {
            bool b = false;
            if (name.Equals("Andy") && age > 30)
            {
                b = true;
            }
            return Json(b);
        }
    }
}

运行效果

https://ithelp.ithome.com.tw/upload/images/20210930/20107452BY94iR4W6b.png

https://ithelp.ithome.com.tw/upload/images/20210930/20107452jvLe98TYqa.png

DataType
用於设定使用显示/编辑模板呈现的模型物件属性转换的HTML控件类型。
以下这些enum选项都可以对应HTML呈现

https://ithelp.ithome.com.tw/upload/images/20210930/20107452ZtXGJpPI0a.png

新建好DataTypeController跟相应Index检视

Index.cshtml

@{
    ViewData["Title"] = "DataType ";
}

@model DataTypeViewModel
<div>
    <input asp-for="Title" />
</div>

DataTypeViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class DataTypeViewModel
    {
        [DataType(DataType.DateTime)]
        public string Title { get; set; }
    }
}

运行效果
https://ithelp.ithome.com.tw/upload/images/20210930/20107452R4fXhlPOWh.png
可以看到原生html input的type我没设置但已经被转为datetime-local的型态
换言之,往後我们可以直接在ViewModel的属性藉由DataType来抉择对应要呈现舍麽样子的html 。

https://ithelp.ithome.com.tw/upload/images/20210930/20107452tDf6Menljm.png

https://ithelp.ithome.com.tw/upload/images/20210930/20107452CVXGNt78Or.png

那前面还有提到所谓可用於设定使用显示/编辑模板呈现
我们改套用编辑模板

这里我们修改多个属性的ViewModel

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class DataTypeViewModel
    {
        [DataType(DataType.EmailAddress)]
        public string Title { get; set; }

        [DataType(DataType.Currency)]
        public int Age { get; set; }
    }
}

Index.cshml部分我们只需要一句就能取代很多行input tag绑定,套用编辑模板。

预设都在HtmlHelper底下很多种和Model相应的模板可用
https://ithelp.ithome.com.tw/upload/images/20210930/201074521X9RZy3hQF.png

这里用@Html.EditorForModel()
https://ithelp.ithome.com.tw/upload/images/20210930/201074522YbcJYplAO.png

运行效果
https://ithelp.ithome.com.tw/upload/images/20210930/20107452gyLvM8XJWn.png

EmailAddress

可将指定该特性的ViewModel属性转为type为email的input tag,可自动套用HTML5邮件格式的验证。

这里新增一个EmailAddressController和相应的Index检视

Index.cshtml

@{
    ViewData["Title"] = "EmailAddress";
}
@model EmailAddressViewModel
<form>
    <div>
        <label asp-for="Email"></label>
        <input asp-for="Email" />
        <span asp-validation-for="Email"></span>
    </div>
    <div>
        <input type="submit" value="提交" />
    </div>
</form>

EmailAddressViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class EmailAddressViewModel
    {
        [Display(Name = "邮件")]
        [EmailAddress()]
        public string Email { get; set; }
    }
}

运行效果
https://ithelp.ithome.com.tw/upload/images/20210930/20107452zWFRJHMzfI.png

Display

前面一直用的主要就是用於做客制化label显示
其包含order属性,默认是采用升幂(序)由小到大排列,对於Display特性的Order属性,可对ViewModel中属性於编辑模板显示顺序进行排列(只限於编辑模板或显示模板)。

新建一个Display控制器和相应Index检视以及DisplayViewModel

Index检视

@{
    ViewData["Title"] = "Display";
}

@model DisplayViewModel
<form>
    <div>
        @Html.EditorForModel()

        @*<label asp-for="Id"></label>
        <input type="text" asp-for="Id" />
        <br />
        <label asp-for="Name"></label>
        <input type="text" asp-for="Name" />
        <br />
        <label asp-for="Sex"></label>
        <input type="checkbox" asp-for="Sex" />*@

    </div>
</form>

DisplayViewModel

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class DisplayViewModel
    {
        [Display(Name="ID",Order =3)]
        public int Id { get; set; }
        [Display(Name="姓名",Order =1)]
        public string Name { get; set; }
        [Display(Name="性别",Order =2)]
        public bool Sex { get; set; }
    }
}

运行效果(预设bool会产生checkbox , ID为数字则呈现number选单)
https://ithelp.ithome.com.tw/upload/images/20210930/201074529DAE38FDyG.png

默认情况下编辑模板会依照属性由上至下依序排列。
https://ithelp.ithome.com.tw/upload/images/20210930/20107452CVO9mqa09o.png

DisplayFormat
该属性可用於对模型物件中属性值进行格式化(Ex:货币、日期时间),藉由
DataFormatString ="格式类型"语法来指定要显示的格式。

新建DisplayFormatController跟相应的Index检视
还有对应ViewModel

DisplayFormatViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class DisplayFormatViewModel
    {
        [Display(Name = "价格")]
        [DisplayFormat(DataFormatString = "{0:C}")]
        public double Price { get; set; }
    }
}

DisplayFormatController.cs

using DotNet5App7.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Controllers
{
    public class DisplayFormatController : Controller
    {
        public IActionResult Index()
        {
            DisplayFormatViewModel model = new DisplayFormatViewModel()
            {
                Price = 45.58
            };
            return View(model);
        }
    }
}

这里用[DisplayFormat(DataFormatString = "{0:C}")]去进行对应金钱格式设置,
该属性可以去判定隶属Server所在国家地理位置来做相应货币格式变换。

Index.cshtml

@{ 
    ViewData["Title"] = "DisplayFormat";
}

@model DisplayFormatViewModel

<div>
    <label asp-for="Price"></label>
    <input type="text" asp-for="Price" />
</div>

当运行时会发现没有套用转为金钱格式的样子

https://ithelp.ithome.com.tw/upload/images/20210930/20107452P5uVtmv0pd.png

原因在於我们目前处於编辑文字输入框的模式
要在对ViewModel中属性做额外ApplyFormatInEditMode为true的设置

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class DisplayFormatViewModel
    {
        [Display(Name = "价格")]
        [DisplayFormat(DataFormatString = "{0:C}", ApplyFormatInEditMode = true)]
        public double Price { get; set; }
    }
}

再次运行即可
https://ithelp.ithome.com.tw/upload/images/20210930/201074526HCcROmXc0.png

编辑模式在此也可用HtmlHelper提供方法搭配lambda语法来取代

@{ 
    ViewData["Title"] = "DisplayFormat";
}

@model DisplayFormatViewModel

<div>
    <label asp-for="Price"></label>
    <input type="text" asp-for="Price" />
    @Html.EditorFor(m=>m.Price)
</div>

https://ithelp.ithome.com.tw/upload/images/20210930/2010745219Tn0bhPDC.png

DisplayFormat中的ConvertEmptyStringToNull默认为true,可将模型的属性值中若是空字串会被转为null。

这里扩充一个string属性Name

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class DisplayFormatViewModel
    {
        [Display(Name = "价格")]
        [DisplayFormat(DataFormatString = "{0:C}", ApplyFormatInEditMode = true)]
        public double Price { get; set; }
        [DisplayFormat(ConvertEmptyStringToNull =false)]
        public string Name { get; set; }
    }
}

在检视我们调整成一个表单提交的画面

@{ 
    ViewData["Title"] = "DisplayFormat";
}

@model DisplayFormatViewModel

<form method="post">
    <div>
        <label asp-for="Price"></label>
        <input type="text" asp-for="Price" />
        @Html.EditorFor(m => m.Price)
    </div>
    <div>
        <label asp-for="Name"></label>
        <input type="text" asp-for="Name" />
        @Html.DisplayFor(m => m.Name)
    </div>
    <div>
        <input type="submit" value="提交" />
    </div>
</form>

DisplayFormatController中调整从View传进来模型接收的POST action method

using DotNet5App7.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Controllers
{
    public class DisplayFormatController : Controller
    {
        public IActionResult Index()
        {
            DisplayFormatViewModel model = new DisplayFormatViewModel()
            {
                Price = 45.58
            };
            return View(model);
        }

        [HttpPost]
        public IActionResult Index(DisplayFormatViewModel model)
        {
            return View(model);
        }
    }
}

运行效果
https://ithelp.ithome.com.tw/upload/images/20210930/20107452VPZefUEOWf.png

若这里不去对属性Name写[DisplayFormat(ConvertEmptyStringToNull =false)]
或者写[DisplayFormat(ConvertEmptyStringToNull =true)]
https://ithelp.ithome.com.tw/upload/images/20210930/20107452EYNRDaUjeE.png

则Server-Side接收到会是null

在DisplayFormat中HtmlEncode属性可协助我们是否要开启或关闭要采用HTML来编码
默认为true启用的。

而NullDisplayText属性则是当属性值为null或空字串("")时,可设置预设为空要显示的默认字串内容。

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace DotNet5App7.Models
{
    public class DisplayFormatViewModel
    {
        [Display(Name = "价格")]
        [DisplayFormat(DataFormatString = "{0:C}", ApplyFormatInEditMode = true)]
        public double Price { get; set; }
        [DisplayFormat(NullDisplayText ="为空时的预设值")]
        public string Name { get; set; }
    }
}

https://ithelp.ithome.com.tw/upload/images/20210930/20107452UA9S60i1wS.png

本文同步发表至个人部落格(分两篇->因为铁人赛规划30天原先blog分两篇章)
.NET Core第29天_Model验证配置准备流程_各种验证资料注解使用方式_part1(Required,StringLength,MaxLength,MinLength,RegularExpression,Range,Compare)
https://coolmandiary.blogspot.com/2021/08/net-core29modelpart1.html

.NET Core第30天_Model验证配置准备流程_各种验证资料注解使用方式_part2(Remote,DataType,EmailAddress,Display,DisplayFormat验证)
https://coolmandiary.blogspot.com/2021/08/net-core30modelpart2remotedatatypeemail.html


<<:  Day30 换脸效果 ( 你全家都同一张脸 )

>>:  Day30 - 铁人付外挂部署与发行(三)- 贩售外挂

DAY26-SQL语法(VIEW应用)

今天要来讲另一个方法,那就是VIEW方法,VIEW方法就是要建立一 个虚拟资料表,资料表本身没有储存...

[Day11] 团队管理:团队共识与团队思考

团队目标的建立 提供对应的元素,催化IT团队与事业体相呼应的目标 身为产品经理,需要清楚知道公司目标...

[Day28] 透过GCP实作(4/4):透过Scheduler与Pub/Sub使抓取资料自动化

基於昨日文章的说明, 我们已经建立了一个资料库协助我们暂存资料资料 但缺乏驱动负责拉取与上传资料的...

[Day25] Esp32s + IFTTT + LINE

1.前言 前两篇使用到日常生活中使用率最高的通讯软件LINE Notify功能,不知道各位小夥伴是否...

Day26练习java-抛出例外

昨天使用的是在有明确资讯时的例外处理,可以直接使用try catch抓出来,但有时在方法里需要传入资...