AutoFac注册多个泛型仓储时仅最后一个生效的原因及解决方案
多数据库场景下AutoFac注册泛型仓储仅最后一个生效问题解决
项目背景
开发面向.NET 5的ASP.NET API项目,需访问三个不同的SQL数据库,使用AutoFac作为DI容器,同时使用CleanArchitecture框架。为每个对应不同数据库的DbContext分别实现了一套泛型仓储。
Startup项目的Startup.cs中ConfigureContainer方法代码如下:
public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterModule(new DefaultCoreModule()); builder.RegisterModule(new DefaultInfrastructureModule(_env.EnvironmentName == "Development")); }
DefaultInfrastructureModule类的初始RegisterCommonDependencies方法代码如下:
private void RegisterCommonDependencies(ContainerBuilder builder) { builder.RegisterGeneric(typeof(IdpRepository<>)) .As(typeof(IRepository<>)) .As(typeof(IReadRepository<>)) .InstancePerLifetimeScope(); builder.RegisterGeneric(typeof(CdRepository<>)) .As(typeof(IRepository<>)) .As(typeof(IReadRepository<>)) .InstancePerLifetimeScope(); builder.RegisterGeneric(typeof(M1Repository<>)) .As(typeof(IRepository<>)) .As(typeof(IReadRepository<>)) .InstancePerLifetimeScope(); // 其他注册逻辑 }
问题现象
项目可正常编译运行,但调用仓储的ListAsync等方法时,只有注册顺序排在最后的仓储可正常工作,其他都会抛出SqlException,提示对象名无效,比如找不到User表,就像是DbContext.Set没有正确识别要查询的复数形式Users表。调整注册顺序后,始终只有最后一个注册的仓储可以正常使用。
三个泛型仓储都遵循CleanArchitecture模板的设计,以CdRepository为例初始实现如下:
public class CdRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T> where T : class { public CdRepository(CdDbContext dbContext) : base(dbContext) { } }
更新1:端点注入代码
注入仓储的ListDepartments端点实现如下:
public class ListDepartments : BaseAsyncEndpoint .WithRequest<DepartmentListRequest> .WithResponse<DepartmentListResponse> { private readonly IReadRepository<Department> _repository; public ListDepartments(IReadRepository<Department> repository) { _repository = repository; } [HttpGet("/Organizations/{OrganizationId}/Departments")] [SwaggerOperation( Summary = "Gets a list of all Departments for the specified Organization ID", Description = "Gets a list of all Departments for the specified Organization ID", OperationId = "Department.ListDepartments", Tags = new[] { "OrganizationEndpoints" }) ] public override async Task<ActionResult<DepartmentListResponse>> HandleAsync([FromQuery] DepartmentListRequest request, CancellationToken cancellationToken) { var response = new DepartmentListResponse(); response.OrganizationId = request.OrganizationId; response.Departments = (await _repository.ListAsync(cancellationToken)) .Select(department => new DepartmentListSummaryRecord(department.Id, department.Name)) .ToList(); return Ok(response); } }
更新2:问题根源与修复方案
问题根源
三个仓储都注册为了相同的IRepository<>和IReadRepository<>接口,AutoFac默认会为接口注入最后一个注册的实现,因此实际注入的永远是对应最后一个注册的仓储的DbContext,访问其他库的业务表自然会报错。
修复方案
为每个仓储定义独有的泛型接口,分别注册。
修改后的各仓储代码:
public class CdRepository<T> : RepositoryBase<T>, ICdReadRepository<T>, ICdRepository<T> where T : class { public CdRepository(CdDbContext dbContext) : base(dbContext) { } } public class IdpRepository<T> : RepositoryBase<T>, IIdpReadRepository<T>, IIdpRepository<T> where T : class { public IdpRepository(IdpDbContext dbContext) : base(dbContext) { } } public class M1Repository<T> : RepositoryBase<T>, IM1ReadRepository<T>, IM1Repository<T> where T : class { public M1Repository(M1DbContext dbContext) : base(dbContext) { } }
修改后的注册代码:
private void RegisterCommonDependencies(ContainerBuilder builder) { builder.RegisterGeneric(typeof(IdpRepository<>)) .As(typeof(IIdpRepository<>)) .As(typeof(IIdpReadRepository<>)) .InstancePerLifetimeScope(); builder.RegisterGeneric(typeof(CdRepository<>)) .As(typeof(ICdRepository<>)) .As(typeof(ICdReadRepository<>)) .InstancePerLifetimeScope(); builder.RegisterGeneric(typeof(M1Repository<>)) .As(typeof(IM1Repository<>)) .As(typeof(IM1ReadRepository<>)) .InstancePerLifetimeScope(); // 其他注册逻辑 }
修改完成后问题得到解决。
内容的提问来源于stack exchange,提问作者whiskytangofoxtrot
相关产品推荐
相关产品推荐

