MediatR封闭泛型EventHandler未被调用问题求助
MediatR泛型事件处理器无法触发的问题
我在项目中用MediatR的Notification实现缓存失效,针对各实体定义了Created、Updated、Deleted三类事件。当前遇到的问题:直接注册泛型UpdatedEventHandler实例时,处理器始终不会被调用;但创建继承自该泛型处理器的显式类后,相同的注册代码就能正常触发Handle方法。
代码详情
1. 事件处理器注册代码
collection.AddTransient( typeof(IEventHandler<UpdatedEvent<RefreshToken, RefreshTokenId>>), typeof(UpdatedEventHandler<IRefreshTokenRepository, RefreshToken, RefreshTokenId, IRefreshTokenDto, UpdatedEvent<RefreshToken, RefreshTokenId>>));
2. 通知发布代码
await _mediator.Publish(new UpdatedEvent<RefreshToken, RefreshTokenId>(new RefreshToken(new UserId())), cancellationToken);
3. 泛型事件处理器实现
public class UpdatedEventHandler<TIRepository, TEntity, TId, TIDto, TUpdated> : IEventHandler<TUpdated> where TUpdated : UpdatedEvent<TEntity, TId> where TIRepository : IRepository<TEntity, TId, TIDto> where TEntity : Entity<TId> where TId : IdObject<TId> where TIDto : IDto<TId> { private readonly TIRepository _repository; public UpdatedEventHandler(TIRepository repository) { _repository = repository; } public Task Handle(TUpdated updatedEvent, CancellationToken cancellationToken) { var _cacheKeys = GetBaseCacheKeysAsync(updatedEvent); return _repository.ClearCacheAsync(_cacheKeys); } private async IAsyncEnumerable<string> GetBaseCacheKeysAsync(TUpdated updatedEvent) { yield return await _repository.EntityValueCacheKeyAsync(nameof(_repository.GetByIdAsync), updatedEvent.Updated.Id.Value.ToString()); yield return await _repository.EntityCacheKeyAsync(nameof(_repository.GetListAsync)); await foreach (var cacheKey in GetCacheKeysAsync(updatedEvent)) { yield return cacheKey; } } protected virtual IAsyncEnumerable<string> GetCacheKeysAsync(TUpdated updatedEvent) { throw new NotImplementedException("Override this method to add additional cache keys."); } }
有效对比:显式继承类
创建如下显式继承类后,注册代码不变即可正常触发处理器:
public class RefreshTokenUpdatedEventHandler : UpdatedEventHandler<IRefreshTokenRepository, RefreshToken, RefreshTokenId, IRefreshTokenDto, UpdatedEvent<RefreshToken, RefreshTokenId>> { public RefreshTokenUpdatedEventHandler(IRefreshTokenRepository repository) : base(repository) { } }
解决方案
问题根源是MediatR对嵌套泛型闭包类型的解析支持有限,无法正确识别包含泛型事件参数的处理器类型。以下是三种解决方式:
方式1:使用MediatR批量注册扩展
放弃手动单个注册,改用框架提供的批量扫描注册,让MediatR自动识别所有处理器类型(包括泛型闭包):
// 扫描泛型处理器所在的程序集 collection.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(UpdatedEventHandler<,,,,>).Assembly));
方式2:简化泛型处理器的类型参数
移除事件类型的泛型参数,通过约束自动推导事件类型,降低嵌套泛型复杂度:
public class UpdatedEventHandler<TIRepository, TEntity, TId, TIDto> : IEventHandler<UpdatedEvent<TEntity, TId>> where TIRepository : IRepository<TEntity, TId, TIDto> where TEntity : Entity<TId> where TId : IdObject<TId> where TIDto : IDto<TId> { private readonly TIRepository _repository; public UpdatedEventHandler(TIRepository repository) { _repository = repository; } public Task Handle(UpdatedEvent<TEntity, TId> updatedEvent, CancellationToken cancellationToken) { var _cacheKeys = GetBaseCacheKeysAsync(updatedEvent); return _repository.ClearCacheAsync(_cacheKeys); } private async IAsyncEnumerable<string> GetBaseCacheKeysAsync(UpdatedEvent<TEntity, TId> updatedEvent) { yield return await _repository.EntityValueCacheKeyAsync(nameof(_repository.GetByIdAsync), updatedEvent.Updated.Id.Value.ToString()); yield return await _repository.EntityCacheKeyAsync(nameof(_repository.GetListAsync)); await foreach (var cacheKey in GetCacheKeysAsync(updatedEvent)) { yield return cacheKey; } } protected virtual IAsyncEnumerable<string> GetCacheKeysAsync(UpdatedEvent<TEntity, TId> updatedEvent) { throw new NotImplementedException("Override this method to add additional cache keys."); } }
注册代码简化为:
collection.AddTransient( typeof(IEventHandler<UpdatedEvent<RefreshToken, RefreshTokenId>>), typeof(UpdatedEventHandler<IRefreshTokenRepository, RefreshToken, RefreshTokenId, IRefreshTokenDto>));
方式3:保留显式继承类(临时方案)
若不想修改现有代码结构,可继续使用显式继承类的方式,虽然增加了代码量,但能确保MediatR正确识别处理器。
内容的提问来源于stack exchange,提问作者Yannik Köllmann
相关产品推荐
相关产品推荐

