C#中动态构造事件处理器处理DDD领域事件的依赖注入问题
Absolutely, you can get Autofac to inject dependencies into your domain event handlers—this is exactly the fix you need for that MissingMethodException. The root issue here is that Activator.CreateInstance can only instantiate classes with a parameterless constructor, but your handler needs an IOrderHistoryRepository dependency that Autofac should be managing. Let's rework your domain event infrastructure to leverage Autofac's container for resolving handlers, which will automatically inject any required services.
Step 1: Refactor Your Domain Event Dispatcher to Use Autofac
Instead of relying on Activator.CreateInstance, your dispatcher should pull handlers directly from Autofac's lifetime scope. This ensures dependencies are injected properly. Here's how to adjust your DomainEventsDispatcher:
public class DomainEventsDispatcher { private readonly ILifetimeScope _lifetimeScope; // Inject Autofac's lifetime scope via constructor public DomainEventsDispatcher(ILifetimeScope lifetimeScope) { _lifetimeScope = lifetimeScope; } public async Task DispatchEventsAsync(IEnumerable<IDomainEvent> domainEvents) { foreach (var domainEvent in domainEvents) { // Resolve all handlers for the current event type var handlerType = typeof(IHandler<>).MakeGenericType(domainEvent.GetType()); var handlers = _lifetimeScope.ResolveAll(handlerType); // Invoke each handler (using dynamic to avoid messy reflection) foreach (dynamic handler in handlers) { await handler.HandleAsync((dynamic)domainEvent); } } } }
Step 2: Register All Event Handlers with Autofac
Tell Autofac to automatically register every class that implements your IHandler<T> interface. This saves you from manually registering each handler one by one. Add this to your Autofac container setup:
var builder = new ContainerBuilder(); // Register all domain event handlers from your assembly (replace with your marker type) builder.RegisterAssemblyTypes(typeof(OrderHistoryCreatedHandler).Assembly) .AsClosedTypesOf(typeof(IHandler<>)) .InstancePerLifetimeScope(); // Register your dispatcher as a scoped service builder.RegisterType<DomainEventsDispatcher>() .InstancePerLifetimeScope(); // Don't forget to register your repository dependency builder.RegisterType<OrderHistoryRepository>() .As<IOrderHistoryRepository>() .InstancePerLifetimeScope(); // Build the container and integrate with ASP.NET Core var container = builder.Build(); // ... rest of your ASP.NET Core setup to use Autofac as the DI provider
Step 3: Inject the Dispatcher into Your DbContext
Update your custom DbContext to accept the DomainEventsDispatcher via constructor injection, instead of using a static DomainEvents class. This keeps your code decoupled and aligned with DI best practices:
public class AppDbContext : DbContext { private readonly DomainEventsDispatcher _eventsDispatcher; public AppDbContext( DbContextOptions<AppDbContext> options, DomainEventsDispatcher eventsDispatcher) : base(options) { _eventsDispatcher = eventsDispatcher; } public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { // Collect all domain events from tracked entities first var domainEvents = ChangeTracker.Entries<YourBaseEntityType>() .Where(entry => entry.Entity.DomainEvents.Any()) .SelectMany(entry => entry.Entity.DomainEvents) .ToList(); // Save changes to the database first var saveResult = await base.SaveChangesAsync(cancellationToken); // Dispatch events AFTER saving (ensures events are based on persisted state) await _eventsDispatcher.DispatchEventsAsync(domainEvents); // Clear events from entities to avoid re-dispatching later foreach (var entry in ChangeTracker.Entries<YourBaseEntityType>()) { entry.Entity.ClearDomainEvents(); } return saveResult; } }
Key Notes to Avoid Pitfalls
- Skip Static Domain Events Classes: Static classes holding container references can lead to memory leaks or incorrect service lifetimes. Using an injected dispatcher is far safer.
- Lifetime Alignment:
InstancePerLifetimeScopeensures your handlers and their dependencies (like repositories) are scoped to the current request—ideal for ASP.NET Core web apps. - Support Multiple Handlers:
ResolveAlllets you attach multiple handlers to a single domain event, a common and powerful DDD practice.
This setup will eliminate your MissingMethodException because Autofac handles instantiating your handlers with all required constructor dependencies—no parameterless constructor needed.
内容的提问来源于stack exchange,提问作者mirind4

