分布式事件的设计与抽象

This commit is contained in:
hello 2024-09-12 22:01:35 +08:00
parent fb424749c0
commit dbfb59f461
9 changed files with 148 additions and 5 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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<MessageService> logger) : IEmailSender, ISmsSender

View File

@ -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<string, JsonElement>? ExtensionData { get; set; }
}
}

View File

@ -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<JsonSerializerOptions> configure)
{
eventBusBuilder.Services.Configure<DistributedEventBusOptions>(o =>
{
configure(o.JsonSerializerOptions);
});
return eventBusBuilder;
}
public static IDistributedEventBusBuilder AddSubscription<TEvent, TEventHandler>(this IDistributedEventBusBuilder eventBusBuilder) where TEvent : DistributedEvent where TEventHandler : class, IDistributedEventHandler<TEvent>
{
eventBusBuilder.Services.AddKeyedTransient<IDistributedEventHandler, TEventHandler>(typeof(TEvent));
eventBusBuilder.Services.Configure<DistributedEventBusOptions>(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<DistributedEventBusOptions>(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;
}
}
}

View File

@ -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<string, Type> EventTypes { get; } = [];
public JsonSerializerOptions JsonSerializerOptions { get; } = new(DefaultSerializerOptions);
internal static readonly JsonSerializerOptions DefaultSerializerOptions = new()
{
TypeInfoResolver = JsonSerializer.IsReflectionEnabledByDefault ? new DefaultJsonTypeInfoResolver() : JsonTypeInfoResolver.Combine()
};
}
}

View File

@ -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);
}
}

View File

@ -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; }
}
}

View File

@ -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<in TDistributedEvent> : IDistributedEventHandler where TDistributedEvent : DistributedEvent
{
Task HandleAsync(TDistributedEvent @event);
Task IDistributedEventHandler.HandleAsync(DistributedEvent @event) => HandleAsync((TDistributedEvent)@event);
}
}