From 780c489e023fe6ed8324d0fba3f25927cf8c49fc Mon Sep 17 00:00:00 2001 From: hello Date: Fri, 6 Sep 2024 22:42:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=91=BD=E4=BB=A4=E6=A8=A1=E5=BC=8F=E5=92=8C?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E5=B9=82=E7=AD=89=E5=8E=BB=E9=87=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commands/IdentifiedCommand.cs | 14 +++++ .../Commands/IdentifiedCommandHandler.cs | 25 ++++++++ .../Commands/Orders/CreateOrderCommand.cs | 61 +++++++++++++++++++ .../Orders/CreateOrderCommandHandler.cs | 21 +++++++ .../Entities/Idempotency/ClientRequest.cs | 14 +++++ .../Extensions/Extensions.cs | 9 +++ .../HelloShop.OrderingService.csproj | 1 + .../ClientRequestEntityTypeConfiguration.cs | 21 +++++++ .../Services/ClientRequestManager.cs | 30 +++++++++ .../Services/IClientRequestManager.cs | 12 ++++ 10 files changed, 208 insertions(+) create mode 100644 src/HelloShop.OrderingService/Commands/IdentifiedCommand.cs create mode 100644 src/HelloShop.OrderingService/Commands/IdentifiedCommandHandler.cs create mode 100644 src/HelloShop.OrderingService/Commands/Orders/CreateOrderCommand.cs create mode 100644 src/HelloShop.OrderingService/Commands/Orders/CreateOrderCommandHandler.cs create mode 100644 src/HelloShop.OrderingService/Entities/Idempotency/ClientRequest.cs create mode 100644 src/HelloShop.OrderingService/Infrastructure/EntityConfigurations/Idempotency/ClientRequestEntityTypeConfiguration.cs create mode 100644 src/HelloShop.OrderingService/Services/ClientRequestManager.cs create mode 100644 src/HelloShop.OrderingService/Services/IClientRequestManager.cs diff --git a/src/HelloShop.OrderingService/Commands/IdentifiedCommand.cs b/src/HelloShop.OrderingService/Commands/IdentifiedCommand.cs new file mode 100644 index 0000000..f7471a3 --- /dev/null +++ b/src/HelloShop.OrderingService/Commands/IdentifiedCommand.cs @@ -0,0 +1,14 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using MediatR; + +namespace HelloShop.OrderingService.Commands +{ + public class IdentifiedCommand(TRequest command, Guid id) : IRequest where TRequest : IRequest + { + public TRequest Command { get; } = command; + + public Guid Id { get; } = id; + } +} diff --git a/src/HelloShop.OrderingService/Commands/IdentifiedCommandHandler.cs b/src/HelloShop.OrderingService/Commands/IdentifiedCommandHandler.cs new file mode 100644 index 0000000..5a99679 --- /dev/null +++ b/src/HelloShop.OrderingService/Commands/IdentifiedCommandHandler.cs @@ -0,0 +1,25 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using HelloShop.OrderingService.Services; +using MediatR; + +namespace HelloShop.OrderingService.Commands +{ + public abstract class IdentifiedCommandHandler(IMediator mediator, IClientRequestManager requestManager) : IRequestHandler, TResponse> where TRequest : IRequest + { + protected virtual TResponse? CreateResultForDuplicateRequest() => default; + + public async Task Handle(IdentifiedCommand request, CancellationToken cancellationToken) + { + if (await requestManager.ExistAsync(request.Id)) + { + return CreateResultForDuplicateRequest() ?? throw new NotImplementedException(); + } + + await requestManager.CreateRequestForCommandAsync(request.Id); + + return await mediator.Send(request.Command, cancellationToken); + } + } +} diff --git a/src/HelloShop.OrderingService/Commands/Orders/CreateOrderCommand.cs b/src/HelloShop.OrderingService/Commands/Orders/CreateOrderCommand.cs new file mode 100644 index 0000000..cf5fec7 --- /dev/null +++ b/src/HelloShop.OrderingService/Commands/Orders/CreateOrderCommand.cs @@ -0,0 +1,61 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using MediatR; + +namespace HelloShop.OrderingService.Commands.Orders +{ + public class CreateOrderCommand : IRequest + { + public int UserId { get; set; } + + public required string UserName { get; set; } + + #region Order Items + + public required IEnumerable OrderItems { get; set; } + + #endregion + + #region PaymentMethod + + public required string CardAlias { get; set; } + + public required string CardNumber { get; set; } + + public required string CardHolderName { get; set; } + + public string? CardSecurityNumber { get; set; } + + public DateTimeOffset? CardExpiration { get; set; } + + #endregion + + #region Address + + public required string Country { get; set; } + + public required string State { get; set; } + + public required string City { get; set; } + + public required string Street { get; set; } + + public required string ZipCode { get; set; } + + #endregion + + public class CreateOrderCommandItem + { + public int ProductId { get; set; } + + public required string ProductName { get; set; } + + public required string PictureUrl { get; set; } + + public decimal UnitPrice { get; set; } + + public int Units { get; set; } + } + } +} diff --git a/src/HelloShop.OrderingService/Commands/Orders/CreateOrderCommandHandler.cs b/src/HelloShop.OrderingService/Commands/Orders/CreateOrderCommandHandler.cs new file mode 100644 index 0000000..1d9c612 --- /dev/null +++ b/src/HelloShop.OrderingService/Commands/Orders/CreateOrderCommandHandler.cs @@ -0,0 +1,21 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using HelloShop.OrderingService.Services; +using MediatR; + +namespace HelloShop.OrderingService.Commands.Orders +{ + public class CreateOrderCommandHandler : IRequestHandler + { + public Task Handle(CreateOrderCommand request, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + } + + public class CreateOrderIdentifiedCommandHandler(IMediator mediator, IClientRequestManager requestManager) : IdentifiedCommandHandler(mediator, requestManager) + { + protected override bool CreateResultForDuplicateRequest() => default; + } +} diff --git a/src/HelloShop.OrderingService/Entities/Idempotency/ClientRequest.cs b/src/HelloShop.OrderingService/Entities/Idempotency/ClientRequest.cs new file mode 100644 index 0000000..be32a85 --- /dev/null +++ b/src/HelloShop.OrderingService/Entities/Idempotency/ClientRequest.cs @@ -0,0 +1,14 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +namespace HelloShop.OrderingService.Entities.Idempotency +{ + public class ClientRequest + { + public Guid Id { get; set; } + + public required string Name { get; set; } + + public DateTimeOffset Time { get; set; } + } +} diff --git a/src/HelloShop.OrderingService/Extensions/Extensions.cs b/src/HelloShop.OrderingService/Extensions/Extensions.cs index 28c9048..b617b94 100644 --- a/src/HelloShop.OrderingService/Extensions/Extensions.cs +++ b/src/HelloShop.OrderingService/Extensions/Extensions.cs @@ -3,8 +3,10 @@ using HelloShop.OrderingService.Constants; using HelloShop.OrderingService.Infrastructure; +using HelloShop.OrderingService.Services; using HelloShop.ServiceDefaults.Extensions; using Microsoft.EntityFrameworkCore; +using System.Reflection; namespace HelloShop.OrderingService.Extensions { @@ -18,6 +20,13 @@ namespace HelloShop.OrderingService.Extensions { options.UseNpgsql(builder.Configuration.GetConnectionString(DbConstants.MasterConnectionStringName)); }); + + builder.Services.AddScoped(); + + builder.Services.AddMediatR(options => + { + options.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()); + }); } public static WebApplication MapApplicationEndpoints(this WebApplication app) diff --git a/src/HelloShop.OrderingService/HelloShop.OrderingService.csproj b/src/HelloShop.OrderingService/HelloShop.OrderingService.csproj index 7fe73e5..b92c965 100644 --- a/src/HelloShop.OrderingService/HelloShop.OrderingService.csproj +++ b/src/HelloShop.OrderingService/HelloShop.OrderingService.csproj @@ -8,6 +8,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/HelloShop.OrderingService/Infrastructure/EntityConfigurations/Idempotency/ClientRequestEntityTypeConfiguration.cs b/src/HelloShop.OrderingService/Infrastructure/EntityConfigurations/Idempotency/ClientRequestEntityTypeConfiguration.cs new file mode 100644 index 0000000..f87c1cc --- /dev/null +++ b/src/HelloShop.OrderingService/Infrastructure/EntityConfigurations/Idempotency/ClientRequestEntityTypeConfiguration.cs @@ -0,0 +1,21 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using HelloShop.OrderingService.Entities.Idempotency; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace HelloShop.OrderingService.Infrastructure.EntityConfigurations.Idempotency +{ + public class ClientRequestEntityTypeConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("ClientRequests"); + + builder.HasKey(t => t.Id); + + builder.Property(t => t.Name).HasMaxLength(64); + } + } +} diff --git a/src/HelloShop.OrderingService/Services/ClientRequestManager.cs b/src/HelloShop.OrderingService/Services/ClientRequestManager.cs new file mode 100644 index 0000000..6d2fd9b --- /dev/null +++ b/src/HelloShop.OrderingService/Services/ClientRequestManager.cs @@ -0,0 +1,30 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using HelloShop.OrderingService.Entities.Idempotency; +using HelloShop.OrderingService.Infrastructure; + +namespace HelloShop.OrderingService.Services +{ + public class ClientRequestManager(OrderingServiceDbContext dbContext) : IClientRequestManager + { + public async Task ExistAsync(Guid id) => await dbContext.FindAsync(id) is not null; + + public async Task CreateRequestForCommandAsync(Guid id) + { + if (await ExistAsync(id)) + { + throw new Exception($"Request with {id} already exists"); + } + + await dbContext.AddAsync(new ClientRequest + { + Id = id, + Name = typeof(T).Name, + Time = DateTime.UtcNow + }); + + await dbContext.SaveChangesAsync(); + } + } +} diff --git a/src/HelloShop.OrderingService/Services/IClientRequestManager.cs b/src/HelloShop.OrderingService/Services/IClientRequestManager.cs new file mode 100644 index 0000000..46dedc7 --- /dev/null +++ b/src/HelloShop.OrderingService/Services/IClientRequestManager.cs @@ -0,0 +1,12 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +namespace HelloShop.OrderingService.Services +{ + public interface IClientRequestManager + { + Task ExistAsync(Guid id); + + Task CreateRequestForCommandAsync(Guid id); + } +} \ No newline at end of file