哈Ha!我继续在网上商店学习Blazor。在本部分中,我将讨论如何添加创建订单,查看订单和执行一系列操作的功能,其中之一可能会导致错误。有关详细信息,欢迎来猫。内容
参考文献
→ 来源→ Docker注册表上的映像佐贺
我很无聊,我决定模仿这种情况,因为我们有两个微服务-用于购物篮和下订单。通常,对于这种情况,将创建微服务协调器,该微服务协调器控制动作的顺序并执行补偿动作。例如,它内置于MassTransit,NServiceBus,MS Orleans(分布式事务)中。例如,当您需要关闭没有机会进行更改的两个不同服务时,我决定模拟一种情况。以Google和FaceBook为例。尽管最好通过服务器执行此操作,然后向后端发送一个请求。这是最简单的例子。更为复杂的一点是将不完整状态保存在LocalStorage浏览器中,并尝试按计时器回滚,但不像我在这里那样笨拙。OrdersViewModel代码: public async Task Create()
{
await _basket.Load();
if (!string.IsNullOrWhiteSpace(_basket.Error))
return;
var lines = _basket.Model.Select(l => new LineModel()
{
Product = new ProductModel()
{
Id = l.Product.Id,
Price = l.Product.Price,
Title = l.Product.Title,
Version = l.Product.Version
},
Quantity = l.Quantity
}).ToList();
await _basket.Clear();
if (!string.IsNullOrWhiteSpace(_basket.Error))
return;
try
{
await _order.Create(lines, Address);
}
catch
{
await Restore(lines);
throw;
}
if (!string.IsNullOrWhiteSpace(_order.Error))
{
await Restore(lines);
}
State = OrderVmState.List;
}
private async Task Restore(IEnumerable<LineModel> lines)
{
foreach (var line in lines)
{
for (int i = 0; i < line.Quantity; i++)
{
await _basket.Add(line.Product);
}
}
}
编码
1)型号
public class LineModel
{
public uint Quantity { get; set; }
public ProductModel Product { get; set; }
}
public enum OrderStatus
{
Created = 10,
Delivered,
}
public class OrderModel
{
public Guid Id { get; set; }
public string Buyer { get; set; }
public OrderStatus Status { get; set; }
public List<LineModel> Lines { get; set; } = new List<LineModel>();
public string Address { get; set; }
}
2)服务
public sealed class OrderService : IOrderService
{
private readonly IApiRepository _api;
private List<OrderModel> _orders;
public OrderService(IApiRepository api)
{
_api = api;
_orders = new List<OrderModel>();
}
public string Error { get; private set; }
public IReadOnlyList<OrderModel> Orders => _orders?.AsReadOnly();
public async Task Create(IEnumerable<LineModel> lines, string address)
{
var (_, e) = await _api.CreateOrder(lines, address);
Error = e;
if (!string.IsNullOrWhiteSpace(e))
return;
await Load();
}
public async Task Load()
{
var (r, e) = await _api.GetOrders();
_orders = r;
Error = e;
}
}
3)ViewModel
public class OrdersViewModel
{
private readonly IOrderService _order;
private readonly IBasketService _basket;
public OrdersViewModel(IOrderService order, IBasketService basket)
{
_order = order;
_basket = basket;
OrderFormContext = new EditContext(this);
}
public bool CanCreateOrder => _basket.ItemsCount > 0;
public string Error => _order.Error + _basket.Error;
public IReadOnlyList<OrderModel> Model => _order.Orders;
public decimal Sum => _basket.Model.Sum(m => m.Quantity * m.Product.Price);
public EditContext OrderFormContext { get; }
public OrderVmState State { get; set; }
[Required]
[StringLength(255, MinimumLength = 3)]
public string Address { get; set; }
public void ChangeState(string value)
{
State = OrderVmState.List;
if (string.IsNullOrWhiteSpace(value))
return;
if (Enum.TryParse(value, true, out OrderVmState state))
State = state;
if (_basket.ItemsCount == 0 && State == OrderVmState.Create)
State = OrderVmState.List;
}
public async Task OnInitializedAsync()
{
await _order.Load();
await _basket.Load();
}
public async Task Create()
{
if (!OrderFormContext.Validate())
return;
await _basket.Load();
if (!string.IsNullOrWhiteSpace(_basket.Error))
return;
var lines = _basket.Model.Select(l => new LineModel()
{
Product = new ProductModel()
{
Id = l.Product.Id,
Price = l.Product.Price,
Title = l.Product.Title,
Version = l.Product.Version
},
Quantity = l.Quantity
}).ToList();
await _basket.Clear();
if (!string.IsNullOrWhiteSpace(_basket.Error))
return;
try
{
await _order.Create(lines, Address);
}
catch
{
await Restore(lines);
throw;
}
if (!string.IsNullOrWhiteSpace(_order.Error))
{
await Restore(lines);
}
State = OrderVmState.List;
}
private async Task Restore(IEnumerable<LineModel> lines)
{
foreach (var line in lines)
{
for (int i = 0; i < line.Quantity; i++)
{
await _basket.Add(line.Product);
}
}
}
}
4)查看
@page "/orders"
@page "/orders/{operation}"
@attribute [Authorize]
@inject OrdersViewModel ViewModel
<h3>Orders</h3>
<div>
<Error Model="@ViewModel.Error" />
</div>
@if (ViewModel.State == OrderVmState.Create)
{
<EditForm EditContext="@ViewModel.OrderFormContext" OnValidSubmit="@ViewModel.Create">
<DataAnnotationsValidator />
<div class="form-group"><label class="form-label"> Sum: @ViewModel.Sum</label></div>
<div class="form-group">
<label class="form-label" for="address">Address</label>
<InputTextArea id="address" name="address" class="form-control" @bind-Value="@ViewModel.Address" />
<ValidationMessage For="@(() => ViewModel.Address)" />
</div>
<button type="submit" class="btn btn-primary" disabled="@(!context.Validate())">Save</button>
<button class="btn btn-default" @onclick="@(x => ViewModel.State = OrderVmState.List)">Cancel</button>
</EditForm>
}
else
{
@if (ViewModel.CanCreateOrder)
{
<input type="button" class="btn btn-primary" value="Create Order" @onclick="@(x=>ViewModel.State = OrderVmState.Create)" />
}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<AuthorizeView Roles="admin">
<Authorized>
<th>Id</th>
<th>Buyer Id</th>
</Authorized>
</AuthorizeView>
<th>Status</th>
<th>Products Count</th>
<th>Sum</th>
<th>Address</th>
</tr>
</thead>
<tbody>
@if (ViewModel.Model == null)
{
<tr>
<td>
<em>Loading...</em>
</td>
</tr>
}
else
{
foreach (var order in ViewModel.Model)
{
<tr>
<AuthorizeView Roles="admin">
<Authorized>
<td>@order.Id</td>
<td>@order.Buyer</td>
</Authorized>
</AuthorizeView>
<td>@order.Status.ToString("G")</td>
<td>@order.Lines.Sum(l => l.Quantity)</td>
<td>@order.Lines.Sum(l => l.Quantity * l.Product.Price)</td>
<td>@order.Address</td>
</tr>
}
}
</tbody>
</table>
</div>
}
@functions {
[Parameter]
public string Operation
{
get => ViewModel.State.ToString("G");
set => ViewModel.ChangeState(value);
}
protected override async Task OnInitializedAsync()
{
await ViewModel.OnInitializedAsync();
}
}
屏幕截图


Angular 9上的选项
