ASP.NET 核心中未触发自定义客户端验证
Custom Client-Side Validation not triggering in ASP.NET Core
我正在向我的代码添加一个自定义验证属性,它在服务器端完美运行。但是,在客户端,注册了方法和适配器,但从未调用验证函数。
我正在使用 MVC 在 .NET Core 2.2 中工作。我已经按照其他地方的建议删除了 $(Document).Ready 包装器,并验证了所有外壳都匹配。
下面是一个MRE
测试验证属性:
public class TestValidationAttribute : ValidationAttribute, IClientModelValidator
{
public TestValidationAttribute(string name)
{
_name = name;
}
private string _name;
protected override ValidationResult IsValid(Object value, ValidationContext validationContext)
{
return new ValidationResult($"{_name} has been validated");
}
void IClientModelValidator.AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-testvalidation", $"{_name} has been validated client side");
context.Attributes.Add("data-val-testvalidation-name", _name);
}
}
模特:
public class TestModel
{
[TestValidation("Hello World!")]
[Display(Name = "Test Value")]
public string TestValue { get; set; }
}
视图:
<div class="form-group">
@using (Html.BeginForm())
{
<div class="row">
@Html.LabelFor(m => m.TestValue)
</div>
<div class="row">
@Html.EditorFor(m => m.TestValue)
</div>
<div class="row">
@Html.ValidationMessageFor(m => m.TestValue)
</div>
<div class="row">
<input type="submit" value="Submit" />
</div>
}
</div>
验证 JS:
$(function ($) {
$.validator.addMethod('testvalidation',
function (value, element, params) {
return false;
});
$.validator.unobtrusive.adapters.add('testvalidation', ['name'],
function (options) {
options.rules['testvalidation'] = { name: options.params['name'] };
options.messages['testvalidation'] = options.messages;
});
}(jQuery));
生成的HTML:
<div class="form-group">
<form action="/" method="post"> <div class="row">
<label for="TestValue">Test Value</label>
</div>
<div class="row">
<input class="text-box single-line" data-val="true" data-val-testvalidation="Hello World! has been validated client side" data-val-testvalidation-name="Hello World!" id="TestValue" name="TestValue" type="text" value="" />
</div>
<div class="row">
<span class="field-validation-valid" data-valmsg-for="TestValue" data-valmsg-replace="true"></span>
</div>
<div class="row">
<input type="submit" value="Submit" />
</div>
<input name="__RequestVerificationToken" type="hidden" value="" /></form></div>
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2019 - WebApplication1 - <a href="/Home/Privacy">Privacy</a>
</div>
</footer>
<script src="/lib/jquery/dist/jquery.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
<script src="/js/testvalidation.js"></script>
<script src="/js/site.js?v=4q1jwFhaPaZgr8WAUSrux6hAuh0XDg9kPS3xIVq36I0"></script>
我根据您的问题和代码创建了一个工作示例。
public class TestModel
{
[TestValidation("Hello world!", ErrorMessage = "You did not write Hello world!.")]
[Display(Name = "Test Value")]
public string TestValue { get; set; }
}
[AttributeUsage(AttributeTargets.Property)]
public class TestValidationAttribute : ValidationAttribute, IClientModelValidator
{
private object _expectedValue;
public TestValidationAttribute(object expectedValue)
{
_expectedValue = expectedValue;
}
public override bool IsValid(object value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
return Equals(value, _expectedValue);
}
public void AddValidation(ClientModelValidationContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-testvalidation", ErrorMessage);
context.Attributes.Add("data-val-testvalidation-expectedvalue", _expectedValue.ToString());
}
}
Note that, jQuery validation registers its rules before the DOM is loaded. If you try to register your adapter after the DOM is loaded, your rules will not be processed. So wrap it in a self-executing function.
$(function ($) {
$.validator.addMethod('testvalidation', function (value, element, params) {
var expectedValue = params.expectedvalue;
if (!expectedValue) return false;
var actual = element.value;
if (actual === expectedValue) return true;
return false;
});
$.validator.unobtrusive.adapters.add('testvalidation', ['expectedvalue'],
function (options) {
// Add validation rule for HTML elements that contain data-testvalidation attribute
options.rules['testvalidation'] = {
// pass the data from data-testvalidation-expectedvalue to
// the params argument of the testvalidation method
expectedvalue: options.params['expectedvalue']
};
// get the error message from data-testvalidation-expectedvalue
// so that unobtrusive validation can use it when validation rule fails
options.messages['testvalidation'] = options.message;
});
}(jQuery));
加载脚本的正确方法是
@section Scripts{
@Html.Partial("_ValidationScriptsPartial"); // Or instead like this:
<!--<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>-->
<!--<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js">-->
<script src="~/js/testvalidation.js"></script>
}
您需要将 options.params['name']
更改为 options.params.name
。
这是一个简单的解决方法,如下所示:
<script>
$.validator.addMethod('testvalidation',
function (value, element, params) {
if (value == "") {
return false;
}
return true;
},"Please set a value");
$.validator.unobtrusive.adapters.add('testvalidation', ['name'],
function (options) {
console.log(options);
options.rules['testvalidation'] = { name: options.params.name};
console.log(options.rules['testvalidation']);
options.messages['testvalidation'] = options.message.messages;
});
</script>
结果:
事实证明,我的问题不在于我的代码,而在于我对验证工作方式的理解。我原以为它会在模糊时触发,但直到提交后才触发。
我正在向我的代码添加一个自定义验证属性,它在服务器端完美运行。但是,在客户端,注册了方法和适配器,但从未调用验证函数。
我正在使用 MVC 在 .NET Core 2.2 中工作。我已经按照其他地方的建议删除了 $(Document).Ready 包装器,并验证了所有外壳都匹配。
下面是一个MRE
测试验证属性:
public class TestValidationAttribute : ValidationAttribute, IClientModelValidator
{
public TestValidationAttribute(string name)
{
_name = name;
}
private string _name;
protected override ValidationResult IsValid(Object value, ValidationContext validationContext)
{
return new ValidationResult($"{_name} has been validated");
}
void IClientModelValidator.AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-testvalidation", $"{_name} has been validated client side");
context.Attributes.Add("data-val-testvalidation-name", _name);
}
}
模特:
public class TestModel
{
[TestValidation("Hello World!")]
[Display(Name = "Test Value")]
public string TestValue { get; set; }
}
视图:
<div class="form-group">
@using (Html.BeginForm())
{
<div class="row">
@Html.LabelFor(m => m.TestValue)
</div>
<div class="row">
@Html.EditorFor(m => m.TestValue)
</div>
<div class="row">
@Html.ValidationMessageFor(m => m.TestValue)
</div>
<div class="row">
<input type="submit" value="Submit" />
</div>
}
</div>
验证 JS:
$(function ($) {
$.validator.addMethod('testvalidation',
function (value, element, params) {
return false;
});
$.validator.unobtrusive.adapters.add('testvalidation', ['name'],
function (options) {
options.rules['testvalidation'] = { name: options.params['name'] };
options.messages['testvalidation'] = options.messages;
});
}(jQuery));
生成的HTML:
<div class="form-group">
<form action="/" method="post"> <div class="row">
<label for="TestValue">Test Value</label>
</div>
<div class="row">
<input class="text-box single-line" data-val="true" data-val-testvalidation="Hello World! has been validated client side" data-val-testvalidation-name="Hello World!" id="TestValue" name="TestValue" type="text" value="" />
</div>
<div class="row">
<span class="field-validation-valid" data-valmsg-for="TestValue" data-valmsg-replace="true"></span>
</div>
<div class="row">
<input type="submit" value="Submit" />
</div>
<input name="__RequestVerificationToken" type="hidden" value="" /></form></div>
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2019 - WebApplication1 - <a href="/Home/Privacy">Privacy</a>
</div>
</footer>
<script src="/lib/jquery/dist/jquery.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
<script src="/js/testvalidation.js"></script>
<script src="/js/site.js?v=4q1jwFhaPaZgr8WAUSrux6hAuh0XDg9kPS3xIVq36I0"></script>
我根据您的问题和代码创建了一个工作示例。
public class TestModel
{
[TestValidation("Hello world!", ErrorMessage = "You did not write Hello world!.")]
[Display(Name = "Test Value")]
public string TestValue { get; set; }
}
[AttributeUsage(AttributeTargets.Property)]
public class TestValidationAttribute : ValidationAttribute, IClientModelValidator
{
private object _expectedValue;
public TestValidationAttribute(object expectedValue)
{
_expectedValue = expectedValue;
}
public override bool IsValid(object value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
return Equals(value, _expectedValue);
}
public void AddValidation(ClientModelValidationContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-testvalidation", ErrorMessage);
context.Attributes.Add("data-val-testvalidation-expectedvalue", _expectedValue.ToString());
}
}
Note that, jQuery validation registers its rules before the DOM is loaded. If you try to register your adapter after the DOM is loaded, your rules will not be processed. So wrap it in a self-executing function.
$(function ($) {
$.validator.addMethod('testvalidation', function (value, element, params) {
var expectedValue = params.expectedvalue;
if (!expectedValue) return false;
var actual = element.value;
if (actual === expectedValue) return true;
return false;
});
$.validator.unobtrusive.adapters.add('testvalidation', ['expectedvalue'],
function (options) {
// Add validation rule for HTML elements that contain data-testvalidation attribute
options.rules['testvalidation'] = {
// pass the data from data-testvalidation-expectedvalue to
// the params argument of the testvalidation method
expectedvalue: options.params['expectedvalue']
};
// get the error message from data-testvalidation-expectedvalue
// so that unobtrusive validation can use it when validation rule fails
options.messages['testvalidation'] = options.message;
});
}(jQuery));
加载脚本的正确方法是
@section Scripts{
@Html.Partial("_ValidationScriptsPartial"); // Or instead like this:
<!--<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>-->
<!--<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js">-->
<script src="~/js/testvalidation.js"></script>
}
您需要将 options.params['name']
更改为 options.params.name
。
这是一个简单的解决方法,如下所示:
<script>
$.validator.addMethod('testvalidation',
function (value, element, params) {
if (value == "") {
return false;
}
return true;
},"Please set a value");
$.validator.unobtrusive.adapters.add('testvalidation', ['name'],
function (options) {
console.log(options);
options.rules['testvalidation'] = { name: options.params.name};
console.log(options.rules['testvalidation']);
options.messages['testvalidation'] = options.message.messages;
});
</script>
结果:
事实证明,我的问题不在于我的代码,而在于我对验证工作方式的理解。我原以为它会在模糊时触发,但直到提交后才触发。