該賞金過期5天。此問題的答案有資格獲得 100聲望獎勵。 哈格爾想引起更多人對這個問題的關注。
我正在實作自定義驗證屬性。該屬性不僅查看它所應用的屬性的值,還查看另一個屬性的值。另一個屬性由其名稱指定。
我需要找到一種方法來獲取其他屬性的輸入在最終 HTML 輸出中將具有的完整 ID。
這是我的驗證屬性的簡化版本:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class MyCustomValidationAttribute : ValidationAttribute, IClientModelValidator
{
private string _otherPropertyName;
public MyCustomValidationAttribute(string otherPropertyName)
{
_otherPropertyName = otherPropertyName;
}
protected override ValidationResult IsValid(object value, ValidationContext context)
{
var otherProperty = context.ObjectInstance.GetType().GetProperty(_otherPropertyName);
var otherPropertyValue = Convert.ToString(otherProperty.GetValue(context.ObjectInstance, null));
// Validation logic...
}
public void AddValidation(ClientModelValidationContext context)
{
MergeAttribute(context.Attributes, "data-val", "true");
var errorMessage = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
MergeAttribute(context.Attributes, "data-val-mycustomvalidation", errorMessage);
// THIS ROW NEEDS TO BE FIXED
MergeAttribute(context.Attributes, "data-val-mycustomvalidation-otherpropertyname", _otherProperyName);
}
private void MergeAttribute(IDictionary<string, string> attributes, string key, string value)
{
if (!attributes.ContainsKey(key))
{
attributes.Add(key, value);
}
}
}
這演示了如何在模型類中使用它:
public class Report
{
[MyCustomValidation("Value2", ErrorMessage = "Error...")]
public string Value1 { get; set; }
public string Value2 { get; set; }
}
這是確保驗證也在客戶端完成的 JavaScript:
$.validator.addMethod('mycustomvalidation',
function (value, element, parameters) {
var otherPropertyValue = $('#' parameters.otherpropertyname).val();
// Validation logic...
});
$.validator.unobtrusive.adapters.add('mycustomvalidation', ['otherpropertyname'],
function (options) {
options.rules.mycustomvalidation = options.params;
options.messages['mycustomvalidation'] = options.message;
});
My viewmodel for the page/view with the form looks like this:
public MyViewModel
{
public Report MyReport { get; set; }
}
Note that I'm not using Report as my viewmodel, but rather as the type of a property in the viewmodel. This is important since this is the root of my problem...
The code in the view to show the input for Value1 is nothing strange (I'm using Razor Pages):
<div>
<label asp-for="MyReport.Value1"></label>
<input asp-for="MyReport.Value1" />
<span asp-validation-for="MyReport.Value1"></span>
</div>
And the output becomes:
<label for="MyReport_Value1">Value1</label>
<input
type="text"
id="MyReport_Value1"
name="MyReport.Value1"
data-val="true"
data-val-mycustomvalidation="Error..."
data-val-mycustomvalidation-otherpropertyname="Value2"
value=""
>
<span
data-valmsg-for="MyReport.Value1"
data-valmsg-replace="true"
></span>
So the problem is that in the HTML output I need data-val-mycustomvalidation-otherpropertyname to be "MyReport_Value2" instead of just "Value2". Otherwise the validation code won't be able to find the second HTML input (with id MyReport_Value2) and perform the validation.
I figure this must be done in the method AddValidation() in the attribute class, but how do I get the full name that the HTML input will recieve?
我猜有一些方法可以通過使用背景關系引數來獲得它。我見過類似“*.TemplateInfo.GetFullHtmlFieldId(PropertyName)”的例子,但我無法讓它作業。
任何幫助表示贊賞!
uj5u.com熱心網友回復:
您傳遞Value2給MyCustomValidationAttribute并設定 _otherPropertyName為Value2,并使用
MergeAttribute(context.Attributes, "data-val-mycustomvalidation-otherpropertyname", _otherProperyName);
這樣 html 就會是
data-val-mycustomvalidation-otherpropertyname="Value2"
您只需要傳遞Report_Value2到MyCustomValidationAttribute而不是Value2。
public class Report
{
[MyCustomValidation("Report_Value2", ErrorMessage = "Error...")]
public string Value1 { get; set; }
public string Value2 { get; set; }
}
這樣你就會得到
data-val-mycustomvalidation-otherpropertyname="Report_Value2"
uj5u.com熱心網友回復:
ValidationContext 系結到屬于驗證屬性的實體,即模型。因此定位 ViewModel 的參考看起來很困難。我可以提供三種不同的解決方案,您可以使用哪一種適合您的要求。
解決方案1:
使用 ValidationContext 您可以獲得屬性所屬的類的名稱。只有當 ViewModel 屬性名稱必須與模型類名稱相同時,此解決方案才有效。例如,如果模型類是學生,那么屬性名稱必須是學生。如果屬性名稱是 Student1,它將不起作用。即使類名和屬性名不同,解決方案 2 和 3 也能作業。
模型
public class Student
{
[Key]
public int Id { get; set; }
[Required(ErrorMessage = "Please enter name")]
public string Name { get; set; }
[Required]
[Country("Name")]
public string Country { get; set; }
}
視圖模型
public class StudentViewModel
{
public Student Student {get;set;} //Solution 1 wil not work for Student1
}
驗證屬性
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class CountryAttribute : ValidationAttribute, IClientModelValidator
{
private string _otherPropertyName;
private string _clientPropertyName;
public CountryAttribute(string otherPropertyName)
{
_otherPropertyName = otherPropertyName;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var otherProperty = validationContext.ObjectInstance.GetType().GetProperty(_otherPropertyName);
var otherPropertyValue = Convert.ToString(otherProperty.GetValue(validationContext.ObjectInstance, null));
_clientPropertyName = otherProperty.DeclaringType.Name "_" otherProperty.Name;
}
public void AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-mycustomvalidation-otherpropertyname", _clientPropertyName);
}
}
解決方案2:
Using ClientModelValidationContext you can able to get ViewModel reference that is passed from the controller to view. By using reflection we can get the name of the property i.e Model. To work with solution you need to pass empty ViewModel reference from controller.
Controller
public IActionResult New()
{
StudentViewModel studentViewModel = new StudentViewModel();
return View(studentViewModel);
}
ValidationAttribute
public void AddValidation(ClientModelValidationContext context)
{
var otherClientPropName = context.ModelMetadata.ContainerMetadata.Properties
.Single(p => p.PropertyName == this._otherPropertyName)
.GetDisplayName();
var viewContext = context.ActionContext as ViewContext;
if (viewContext?.ViewData.Model is StudentViewModel)
{
var model = (StudentViewModel)viewContext?.ViewData.Model;
var instanceName = model.GetType().GetProperties()[0].Name;
otherClientPropName = instanceName "_" otherClientPropName;
}
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-mycustomvalidation-otherpropertyname", otherClientPropName);
}
Solution 3:
Using context.Attributes["id"] you can able to get current property id value as string . By using string manipulation you can get prefix then you can merge with other property name. This solution doesn't require empty ViewModel reference from controller.
Controller
public IActionResult New()
{
return View();
}
ValidationAttribute
public void AddValidation(ClientModelValidationContext context)
{
var otherClientPropName = context.ModelMetadata.ContainerMetadata.Properties
.Single(p => p.PropertyName == this._otherPropertyName)
.GetDisplayName();
var id = context.Attributes["id"];
var idPrefix = id.Split("_");
if (idPrefix.Length > 1)
{
otherClientPropName = idPrefix[0] "_" otherClientPropName;
}
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-mycustomvalidation-otherpropertyname", otherClientPropName);
}
HTML Output
<input type="text" data-val="true" data-val-required="Please enter name" id="Student_Name" name="Student.Name" value="">
<input type="text" data-val="true" data-val-mycustomvalidation-otherpropertyname="Student_Name" data-val-required="The Country field is required." id="Student_Country" name="Student.Country" value="">
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/354998.html
