.NET Core 7 Minimal API+MediatR的DI错误排查与解决
运行基于.NET Core 7的Minimal API时,遇到依赖注入相关错误,以下是相关代码与错误信息:
端点代码
public static void DefineEndpoints(IEndpointRouteBuilder app) { app.MapPost(BaseRoute, NewStoredFileTypeAsync) .WithTags(Tag); } private static async Task<Guid> NewStoredFileTypeAsync(NewStoredFileTypeDto request, IMediator mediator) { var messageId = new MessageId(Guid.NewGuid()); var command = new NewStoredFileTypeCommand() { Id = messageId, CorrelationId = new CorrelationId(Guid.Parse(messageId.ToString())), CausationId = new CausationId(Guid.Parse(messageId.ToString())), CommandDto = request, }; var response = await mediator.Send(command); return response; }
命令代码
public class NewStoredFileTypeCommand : BaseCommand, IRequest<Guid> { public NewStoredFileTypeDto CommandDto { get; set; } = default!; }
命令处理器代码
public class NewStoredFileTypeCommandHandler : IRequestHandler<NewStoredFileTypeCommand, Guid> { private readonly IMapper _mapper; private readonly IEventSourcingHandler<StoredFileType, StoredFileTypeId> _eventSourcingHandler; public NewStoredFileTypeCommandHandler(IMapper mapper, IEventSourcingHandler<StoredFileType, StoredFileTypeId> eventSourcingHandler) { _mapper = mapper; _eventSourcingHandler = eventSourcingHandler; } public async Task<Guid> Handle(NewStoredFileTypeCommand request, CancellationToken cancellationToken) { var response = new BaseCommandResponse<StoredFileTypeId>(); var aggregate = new StoredFileType( new StoredFileTypeId(Guid.NewGuid()), request.CorrelationId, new CausationId(Guid.Parse(request.Id.ToString())), request.CommandDto.Name, request.CommandDto.IsImageFileType, _mapper.Map<BootstrapIconCode>(request.CommandDto.BootstrapIconCode) ); await _eventSourcingHandler.SaveAsync(aggregate); return Guid.Parse(aggregate.Id.ToString()); } }
IMongoDbRepository接口
public interface IMongoDbRepository<TEntityId, TEntity> : IRepository<TEntityId, TEntity> { }
MongoDbRepository实现
public class MongoDbRepository<TObjectId, TEntity> : IMongoDbRepository<string, TEntity> where TEntity : IMongoDocument { private readonly IMongoDbSettings _dbSettings; private readonly IMongoCollection<TEntity> _collection; public MongoDbRepository(IMongoDbSettings dbSettings) { _dbSettings = dbSettings; var connectionFactory = new MongoDbConnectionFactory<TEntity>(_dbSettings); _collection = connectionFactory.GetCollection(); } public async Task<bool> InsertAsync(TEntity entity) { await _collection.InsertOneAsync(entity); return true; } public async Task<bool> UpdateAsync(TEntity entity) { throw new NotImplementedException(); } public async Task<bool> DeleteAsync(TEntity entity) { throw new NotImplementedException(); } public async Task<IList<TEntity>> SearchForAsync(Expression<Func<TEntity, bool>> predicate) { return await _collection.Find(predicate).ToListAsync(); } public async Task<IList<TEntity>> GetAllAsync() { return await _collection.Find(_ => true).ToListAsync(); } public async Task<TEntity> GetByIdAsync(string id) { throw new NotImplementedException(); } }
MongoDB仓储注册代码
public static IServiceCollection AddMongoDb(this IServiceCollection services, IConfiguration configuration) { //从appsettings.json获取连接字符串并填充MongoDbSettings类 services.Configure<MongoDbSettings>(configuration.GetSection(nameof(MongoDbSettings))); services.AddSingleton<IMongoDbSettings>(serviceProvider => serviceProvider.GetRequiredService<IOptions<MongoDbSettings>>().Value); //添加泛型仓储 services.AddScoped(typeof(IMongoDbRepository<,>), typeof(MongoDbRepository<,>)); return services; }
错误信息
未处理的异常。System.AggregateException: 无法构造某些服务(验证服务描述符时出错 'ServiceType: MediatR.IRequestHandler
2[mNet.FileServer.Commands.Ui.MinimalApi.Features.StoredFileTypes.NewStoredFileType.NewStoredFileTypeCommand,System.Guid] Lifetime: Transient ImplementationType: mNet.FileServer.Commands.Ui.MinimalApi.Features.StoredFileTypes.NewStoredFileType.NewStoredFileTypeCommandHandler': 实现类型'mNet.Common.Infrastructure.Persistence.MongoDbImplementation.MongoDbRepository2[mNet.FileServer.Commands.Domain.Aggregates.StoredFileTypes.ValueObjects.StoredFileTypeId,mNet.Common.Infrastructure.Persistence.MongoDbImplementation.MongoDbEventDocument`1[mNet.FileServer.Commands.Domain.Aggregates.StoredFileTypes.ValueObjects.StoredFileTypeId]]'无法转换为服务类型'mNet.Common.Infrastructure.Persistence.Contracts.Repositories.IMongoDbRepository`2[mNet.FileServer.Commands.Domain.Aggregates.StoredFileTypes.ValueObjects.StoredFileTypeId,mNet.Common.Infrastructure.Persistence.MongoDbImplementation.MongoDbEventDocument`1[mNet.FileServer.Commands.Domain.Aggregates.StoredFileTypes.ValueObjects.StoredFileTypeId]]')
错误原因
核心问题在于MongoDbRepository的泛型实现与接口不匹配:
- 接口定义为
IMongoDbRepository<TEntityId, TEntity>,允许第一个泛型参数为任意实体ID类型(如你的StoredFileTypeId) - 但你的
MongoDbRepository<TObjectId, TEntity>硬编码实现了IMongoDbRepository<string, TEntity>,固定第一个参数为string - 当DI容器尝试解析
IMongoDbRepository<StoredFileTypeId, MongoDbEventDocument<StoredFileTypeId>>时,找不到匹配的实现,因为你的仓储只实现了string作为ID类型的版本
解决方案
修改MongoDbRepository的实现,使其泛型参数与接口对齐,并处理自定义ID类型与MongoDB字符串ID的转换:
- 调整仓储类的继承关系:
public class MongoDbRepository<TEntityId, TEntity> : IMongoDbRepository<TEntityId, TEntity> where TEntity : IMongoDocument { private readonly IMongoDbSettings _dbSettings; private readonly IMongoCollection<TEntity> _collection; public MongoDbRepository(IMongoDbSettings dbSettings) { _dbSettings = dbSettings; var connectionFactory = new MongoDbConnectionFactory<TEntity>(_dbSettings); _collection = connectionFactory.GetCollection(); } // ... 其他方法保持不变 ... public async Task<TEntity> GetByIdAsync(TEntityId id) { // 假设你的自定义ID类型(如StoredFileTypeId)可以转换为string var stringId = id.ToString(); return await _collection.Find(x => x.Id == stringId).FirstOrDefaultAsync(); } }
确保你的
StoredFileTypeId值对象正确实现ToString()方法,返回对应的Guid字符串(因为MongoDB文档ID通常是字符串格式的Guid)如果你的
IMongoDocument接口定义的Id不是string类型,需要额外处理ID的映射逻辑
内容的提问来源于stack exchange,提问作者dmeadley

