diff --git a/src/HelloShop.OrderingService/Behaviors/TransactionBehavior.cs b/src/HelloShop.OrderingService/Behaviors/TransactionBehavior.cs index 14ff297..fda8b7e 100644 --- a/src/HelloShop.OrderingService/Behaviors/TransactionBehavior.cs +++ b/src/HelloShop.OrderingService/Behaviors/TransactionBehavior.cs @@ -1,4 +1,7 @@ -using HelloShop.OrderingService.Extensions; +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using HelloShop.OrderingService.Extensions; using HelloShop.OrderingService.Infrastructure; using MediatR; using Microsoft.EntityFrameworkCore; diff --git a/src/HelloShop.OrderingService/Controllers/OrdersController.cs b/src/HelloShop.OrderingService/Controllers/OrdersController.cs index 87104f4..bc40e14 100644 --- a/src/HelloShop.OrderingService/Controllers/OrdersController.cs +++ b/src/HelloShop.OrderingService/Controllers/OrdersController.cs @@ -7,10 +7,8 @@ using HelloShop.OrderingService.Commands.Orders; using HelloShop.OrderingService.Models.Orders; using MediatR; using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Components.Forms; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; -using System.ComponentModel.DataAnnotations; using System.Security.Claims; namespace HelloShop.OrderingService.Controllers; diff --git a/src/HelloShop.OrderingService/Services/MessageService.cs b/src/HelloShop.OrderingService/Services/MessageService.cs index e8e43fa..8e61695 100644 --- a/src/HelloShop.OrderingService/Services/MessageService.cs +++ b/src/HelloShop.OrderingService/Services/MessageService.cs @@ -1,8 +1,6 @@ // Copyright (c) HelloShop Corporation. All rights reserved. // See the license file in the project root for more information. -using Microsoft.Extensions.Logging; - namespace HelloShop.OrderingService.Services { public class MessageService(ILogger logger) : IEmailSender, ISmsSender diff --git a/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/DistributedEvent.cs b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/DistributedEvent.cs new file mode 100644 index 0000000..167cf0d --- /dev/null +++ b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/DistributedEvent.cs @@ -0,0 +1,24 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace HelloShop.ServiceDefaults.DistributedEvents.Abstractions +{ + public record DistributedEvent + { + public DistributedEvent() + { + Id = Guid.NewGuid(); + CreationTime = DateTimeOffset.UtcNow; + } + + public Guid Id { get; set; } + + public DateTimeOffset CreationTime { get; set; } + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } + } +} diff --git a/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/DistributedEventBusBuilderExtensions.cs b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/DistributedEventBusBuilderExtensions.cs new file mode 100644 index 0000000..e323725 --- /dev/null +++ b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/DistributedEventBusBuilderExtensions.cs @@ -0,0 +1,61 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using Microsoft.Extensions.DependencyInjection; +using System.Reflection; +using System.Text.Json; + +namespace HelloShop.ServiceDefaults.DistributedEvents.Abstractions +{ + public static class DistributedEventBusBuilderExtensions + { + public static IDistributedEventBusBuilder ConfigureJsonOptions(this IDistributedEventBusBuilder eventBusBuilder, Action configure) + { + eventBusBuilder.Services.Configure(o => + { + configure(o.JsonSerializerOptions); + }); + + return eventBusBuilder; + } + + public static IDistributedEventBusBuilder AddSubscription(this IDistributedEventBusBuilder eventBusBuilder) where TEvent : DistributedEvent where TEventHandler : class, IDistributedEventHandler + { + eventBusBuilder.Services.AddKeyedTransient(typeof(TEvent)); + + eventBusBuilder.Services.Configure(o => + { + o.EventTypes[typeof(TEvent).Name] = typeof(TEvent); + }); + + return eventBusBuilder; + } + + public static IDistributedEventBusBuilder AddSubscription(this IDistributedEventBusBuilder eventBusBuilder, Type eventType, Type eventHandlerType) + { + eventBusBuilder.Services.AddKeyedTransient(typeof(IDistributedEventHandler), eventType, eventHandlerType); + + eventBusBuilder.Services.Configure(o => + { + o.EventTypes[eventType.Name] = eventType; + }); + + return eventBusBuilder; + } + + public static IDistributedEventBusBuilder AddSubscriptionFromAssembly(this IDistributedEventBusBuilder eventBusBuilder, Assembly? assembly = null) + { + assembly ??= Assembly.GetCallingAssembly(); + + var handlers = assembly.GetTypes().Where(t => t.IsAssignableTo(typeof(IDistributedEventHandler))).ToList(); + + handlers.ForEach(handler => + { + var eventType = handler.GetInterfaces().Single(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDistributedEventHandler<>)).GetGenericArguments().Single(); + eventBusBuilder.AddSubscription(eventType, handler); + }); + + return eventBusBuilder; + } + } +} diff --git a/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/DistributedEventBusOptions.cs b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/DistributedEventBusOptions.cs new file mode 100644 index 0000000..d45915a --- /dev/null +++ b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/DistributedEventBusOptions.cs @@ -0,0 +1,20 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using System.Text.Json; +using System.Text.Json.Serialization.Metadata; + +namespace HelloShop.ServiceDefaults.DistributedEvents.Abstractions +{ + public class DistributedEventBusOptions + { + public Dictionary EventTypes { get; } = []; + + public JsonSerializerOptions JsonSerializerOptions { get; } = new(DefaultSerializerOptions); + + internal static readonly JsonSerializerOptions DefaultSerializerOptions = new() + { + TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault ? new DefaultJsonTypeInfoResolver() : JsonTypeInfoResolver.Combine() + }; + } +} diff --git a/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/IDistributedEventBus.cs b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/IDistributedEventBus.cs new file mode 100644 index 0000000..13b1653 --- /dev/null +++ b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/IDistributedEventBus.cs @@ -0,0 +1,10 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +namespace HelloShop.ServiceDefaults.DistributedEvents.Abstractions +{ + public interface IDistributedEventBus + { + Task PublishAsync(DistributedEvent @event, CancellationToken cancellationToken = default); + } +} diff --git a/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/IDistributedEventBusBuilder.cs b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/IDistributedEventBusBuilder.cs new file mode 100644 index 0000000..66e3de5 --- /dev/null +++ b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/IDistributedEventBusBuilder.cs @@ -0,0 +1,12 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +using Microsoft.Extensions.DependencyInjection; + +namespace HelloShop.ServiceDefaults.DistributedEvents.Abstractions +{ + public interface IDistributedEventBusBuilder + { + public IServiceCollection Services { get; } + } +} diff --git a/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/IDistributedEventHandler.cs b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/IDistributedEventHandler.cs new file mode 100644 index 0000000..f139764 --- /dev/null +++ b/src/HelloShop.ServiceDefaults/DistributedEvents/Abstractions/IDistributedEventHandler.cs @@ -0,0 +1,17 @@ +// Copyright (c) HelloShop Corporation. All rights reserved. +// See the license file in the project root for more information. + +namespace HelloShop.ServiceDefaults.DistributedEvents.Abstractions +{ + public interface IDistributedEventHandler + { + Task HandleAsync(DistributedEvent @event); + } + + public interface IDistributedEventHandler : IDistributedEventHandler where TDistributedEvent : DistributedEvent + { + Task HandleAsync(TDistributedEvent @event); + + Task IDistributedEventHandler.HandleAsync(DistributedEvent @event) => HandleAsync((TDistributedEvent)@event); + } +}