我们在 .NET Core 3.1.5 上,这是一个 Blazor 服务器应用程序。
我们有一个 ValidationAttribute 并且需要访问外部服务来验证对象。
ValidationAttribute 有 IsValid 方法:
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
ValidationContext 有一个 GetService 方法,它委托(delegate)给 ServiceProvider 的一个实例。
不幸的是,服务提供者字段从未初始化,因此我们无法检索任何服务。
这是在 Mvc 中提出(并修复)的:aspnet/Mvc#6346
但是我们的验证器是通过以下两个之一调用的:
https://github.com/dotnet/aspnetcore/blob/master/src/Components/Forms/src/EditContextDataAnnotationsExtensions.cs#L47
https://github.com/dotnet/aspnetcore/blob/master/src/Components/Forms/src/EditContextDataAnnotationsExtensions.cs#L75
后来在堆栈中,服务提供者也永远不会设置。
我犹豫是否要打开一个错误(但可以这样做),但这对我来说似乎是错误的(或者至少应该记录在案)。
任何 Google 搜索最终都会出现在这篇博客文章中,但正如我刚才提到的那样,这不起作用。
所以我们的问题是:将服务注入(inject)到 ValidationAttribute 中的正确方法是什么,或者更一般地说,验证需要调用外部服务的模型字段的正确方法是什么?
在 statup.cs
:
services.AddTransient<IMarktTypDaten, MarktTypDaten>();
我们尝试注入(inject)服务并应用验证的类。public class MarktTypNameValidation : ValidationAttribute {
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
var service = (IMarktTypDaten) validationContext.GetRequiredService(typeof(IMarktTypDaten));
...some code...
return ValidationResult.Success;
}
}
调用 GetRequiredService
时出现异常消息: 'No service for type 'DataAccessLibrary.Interfaces.IMarktTypDaten' has been registered.
它也在 Github 上发布:https://github.com/dotnet/aspnetcore/discussions/23305另外:我在 15 年左右第一次使用 C#/.NET,请温柔 ;-)
最佳答案
正如 Steven 在评论部分所建议的那样,你不应该那样做。相反,您可以按照以下代码片段中的描述执行此操作,其中一部分只是伪代码,用于指出您需要做什么......它不应该按原样工作。
您可以为此覆盖 EditContext 的 FieldChanged 方法。
假设您有一个带有电子邮件地址输入字段的表单,并且您想检查此电子邮件是否已被其他用户使用...检查
输入的电子邮件地址的可用性,您必须调用您的数据存储并验证这一点。请注意,FieldChanged 方法中描述的某些操作可以移动到单独的验证服务...
<EditForm EditContext="@EditContext"
OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<div class="form-group">
<label for="name">Name: </label>
<InputText Id="name" Class="form-control" @bind-
Value="@Model.Name"></InputText>
<ValidationMessage For="@(() => Model.Name)" />
</div>
<div class="form-group">
<label for="body">Text: </label>
<InputText Id="body" Class="form-control" @bind-Value="@Model.Text"></InputText>
<ValidationMessage For="@(() => Model.Text)" />
</div>
<div class="form-group">
<label for="body">Email: </label>
<InputText Id="body" Class="form-control" @bind-Value="@Model.EmailAddress"></InputText>
<ValidationMessage For="@(() => Model.EmailAddress)" />
</div>
<p>
<button type="submit">Save</button>
</p>
</EditForm>
@code
{
private EditContext EditContext;
private Comment Model = new Comment();
ValidationMessageStore messages;
protected override void OnInitialized()
{
EditContext = new EditContext(Model);
EditContext.OnFieldChanged += EditContext_OnFieldChanged;
messages = new ValidationMessageStore(EditContext);
base.OnInitialized();
}
// Note: The OnFieldChanged event is raised for each field in the
// model. Here you should validate the email address
private void EditContext_OnFieldChanged(object sender,
FieldChangedEventArgs e)
{
// Call your database to check if the email address is
// available
// Retrieve the value of the input field for email
// Pseudocode...
var email = "enet.xxxx@gmail.com";
var exists = VerifyEmail(email);
messages.Clear();
// If exists is true, form a message about this, and add it
// to the messages object so that it is displayed in the
// ValidationMessage component for email
}
}
希望这可以帮助...
关于c# - 如何在自定义验证属性中获取/注入(inject)服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62559817/