问题描述
我正在学习Blazor,并且有一个WebAssembly客户端应用程序.
I am learning Blazor, and I have a WebAssembly client application.
我在服务器上创建了一个WebAPI,它在标准数据注释验证之上进行了一些附加验证.例如,当它尝试将记录写入数据库时,它会检查是否没有其他记录具有相同的电子邮件地址.某些类型的验证无法可靠地在客户端进行,尤其是在竞争条件可能产生不良结果的地方.
I created a WebAPI at the server which does some additional validation over and above the standard data annotation validations. For example, as it attempts to write a record to the database it checks that no other record exists with the same email address. Certain types of validation can't reliably happen at the client, particularly where race conditions could produce a bad result.
API控制器返回 ValidationProblem 结果发送给客户端,邮递员将结果的正文显示为:
The API controller returns a ValidationProblem result to the client, and Postman shows the body of the result as:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|f06d4ffe-4aa836b5b3f4c9ae.",
"errors": {
"Email": [
"The email address already exists."
]
}
}
请注意,验证错误位于JSON的错误"数组中.
Note that the validation error is in the "errors" array in the JSON.
回到Blazor客户端应用程序中,我具有典型的HandleValidSubmit函数,该函数将数据发布到API并接收响应,如下所示:
Back in the Blazor Client application, I have the typical HandleValidSubmit function that posts the data to the API and receives a response, as shown here:
private async void HandleValidSubmit()
{
var response = await Http.PostAsJsonAsync<TestModel>("api/Test", testModel);
if (response.StatusCode != System.Net.HttpStatusCode.Created)
{
// How to handle server-side validation errors?
}
}
我的问题是,如何最好地处理服务器端验证错误?用户体验应该与任何其他验证错误相同,并突出显示该字段,显示验证消息,并在页面顶部显示摘要.
My question is, how to best process server-side validation errors? The user experience ought to be the same as any other validation error, with the field highlighted, the validation message shown, and the summary at the top of the page.
推荐答案
我最终通过创建ServerValidator组件解决了这个问题.我将在此处发布代码,以防其他人寻求相同问题的解决方案.
I ended up solving this by creating a ServerValidator component. I'll post the code here in case it is helpful for others seeking a solution to the same problem.
此代码假定您正在调用Web API端点,如果存在问题,该端点将返回ValidationProblem结果.
This code assumes you are calling a Web API endpoint that returns a ValidationProblem result if there are issues.
public class ServerValidator : ComponentBase
{
[CascadingParameter]
EditContext CurrentEditContext { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
if (this.CurrentEditContext == null)
{
throw new InvalidOperationException($"{nameof(ServerValidator)} requires a cascading " +
$"parameter of type {nameof(EditContext)}. For example, you can use {nameof(ServerValidator)} " +
$"inside an EditForm.");
}
}
public async void Validate(HttpResponseMessage response, object model)
{
var messages = new ValidationMessageStore(this.CurrentEditContext);
if (response.StatusCode == HttpStatusCode.BadRequest)
{
var body = await response.Content.ReadAsStringAsync();
var validationProblemDetails = JsonSerializer.Deserialize<ValidationProblemDetails>(body);
if (validationProblemDetails.Errors != null)
{
messages.Clear();
foreach (var error in validationProblemDetails.Errors)
{
var fieldIdentifier = new FieldIdentifier(model, error.Key);
messages.Add(fieldIdentifier, error.Value);
}
}
}
CurrentEditContext.NotifyValidationStateChanged();
}
// This is to hold the response details when the controller returns a ValidationProblem result.
private class ValidationProblemDetails
{
[JsonPropertyName("status")]
public int? Status { get; set; }
[JsonPropertyName("title")]
public string Title { get; set; }
[JsonPropertyName("type")]
public string Type { get; set; }
[JsonPropertyName("errors")]
public IDictionary<string, string[]> Errors { get; set; }
}
}
要使用此新组件,您需要在EditForm中添加该组件:
To use this new component, you will need to add the component within your EditForm:
<EditForm Model="agency" OnValidSubmit="HandleValidSubmit">
<ServerValidator @ref="serverValidator" />
<ValidationSummary />
... put all your form fields here ...
</EditForm>
最后,您可以在 @code
部分开始验证:
Lastly, you can kick off the validation in your @code
section:
@code {
private TestModel testModel = new TestModel();
private ServerValidator serverValidator;
private async void HandleValidSubmit()
{
var response = await Http.PostAsJsonAsync<TestModel>("api/TestModels", testModel);
if (response.StatusCode != System.Net.HttpStatusCode.Created)
{
serverValidator.Validate(response, testModel);
}
else
{
Navigation.NavigateTo(response.Headers.Location.ToString());
}
}
}
从理论上讲,这应该允许您完全绕过客户端验证,并依靠Web API进行验证.实际上,我发现即使模型中没有包含< DataAnnotationsValidator/>
,Blazor也会在模型上有注释时执行客户端验证.但是,它仍然会在服务器上捕获任何验证问题并将其返回给您.
In theory, this ought to allow you to bypass client validation entirely and rely on your Web API to do it. In practice, I found that Blazor performs client validation when there are annotations on your model, even if you don't include a <DataAnnotationsValidator />
in your form. However, it will still catch any validation issues at the server and return them to you.
这篇关于处理Blazor WebAssembly中的API验证错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!