You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 02:42:02