我正在进行一个Blazor WebAssembly项目。客户可以通过点击按钮"来创建订单创建订单";。
问题是当用户多次点击按钮时,系统会创建具有相同数据的多个订单(相同的产品、相同的订单号、,等等(。
那么,防止用户创建多个订单的最佳做法是什么?
一个简单的方法是在处理订单后禁用按钮:
Index.razor
:
@page "/"
<button
@onclick="@this.ProcessOrder"
disabled="@this.OrderIsBeingProcessed">
Click me!
</button>
背后的代码Index.razor.cs
:
public partial class Index
{
private bool OrderIsBeingProcessed = false;
private async Task ProcessOrder()
{
this.OrderIsBeingProcessed = true;
// TODO: process order
await Task.Delay(3000);
this.OrderIsBeingProcessed = false;
}
}
请注意,这只是一个如何禁用按钮的(简单(演示,而不是一个防止数据库中重复条目的防傻方法。
那么,防止用户创建多个订单的最佳做法是什么?
最佳做法是在此处重新设计数据流。创建订单时,您应该移动到另一个页面或清除订单输入表单。
清除表单时,下一次单击应该会失败,因为缺少必需的字段。
我假设您使用的是HttpPost,它不是幂等的。在这种情况下,唯一的客户端Id应该会对您有所帮助。这个命令。ClientOrderId可以在服务器端(在数据存储中(进行检查。如果它已经被存储,它就是一个副本。
您也可以在收到服务器的响应时禁用该按钮。
唯一索引将确保在网络故障等情况下或重试期间不会保存重复的订单过账。
POCO:
[Index(nameof(ClientOrderId), IsUnique = true)]
public record Order
{
public int Id { get; init; }
public string ClientOrderId { get; init; }
}
Blazor组件:
<button class="btn btn-info" disabled="@IsSaving" @onclick="@(async () => await SaveAsync())">Save</button>
using System.Net.Http;
public bool IsSaving { get; set; }
[Inject]
private IHttpClientFactory httpClientFactory { get; init; }
private async Task SaveAsync()
{
IsSaving = true;
var order = new Order
{
ClientOrderId = Guid.NewGuid().ToString()
};
try
{
using var httpClient = httpClientFactory.CreateClient();
await httpClient.PostAsJsonAsync("Orders", order).ConfigureAwait(false);
}
catch (Exception exception)
{
//add retry logic
}
finally
{
IsSaving = false;
}
}
Web API控制器后方法
[HttpPost]
public async Task<IActionResult> Post(Order order)
{
var existingOrder = repository.Entities.FirstOrDefaultAsync(c => c.ClientOrderId == order.ClientOrderId);
if(existingOrder)
return CreatedAtAction(actionName, new { id = existingOrder.Id }, existingOrder);
repository.Add(order);
await repository.SaveChangesAsync();
var actionName = nameof(Post);
return CreatedAtAction(actionName, new { id = order.Id }, order);
}