如何使用Autofac将动态DbContext对象注入存储库

时间:2019-07-10 21:00:56

标签: c# entity-framework dependency-injection autofac unit-of-work

我有一个.net核心Web api应用程序,其中我使用带有服务层,工作单元和存储库层模式的实体框架核心。对于DI,我正在使用Autofac。

该应用程序具有多个客户端,并且每个客户端都有自己的数据库,并且所有这些数据库的架构都是相同的。 通过每个API调用,我将获得客户端特定的连接字符串,必须使用该字符串创建一个DbContext并将其用于所有操作。

在启动类中,我已经注册了dbcontext ClientDbContext和所有其他类。调用工作单元类时,我将基于连接字符串创建新的DbContext。我希望存储库使用此实例,,但是存储库仍使用在启动时创建的初始ClientDbContext实例

如何使存储库使用新的DbContext实例?

工作单元:

public class UnitOfWork : IUnitOfWork
{
    public ClientDbContext ClientDbContext { get; private set; }        

    public UnitOfWork ()
    {            

    }

    public void SetDbContext(string connectionString)
    {
        if(ClientDbContext == null)
        {
            //creating new db context instance here
            ClientDbContext = MembershipRepository.CreateDbContext(connectionString);
        }                
    }        
    //property injection
    public IGenericRepository<SomeEntity, ClientDbContext> SomeEntityGenericRepository { get; }
}

通用存储库:

public class GenericRepository<TEntity, TDbContext> : IGenericRepository<TEntity, TDbContext> where TEntity : class
where TDbContext : DbContext
{
    private readonly TDbContext _context;
    private readonly DbSet<TEntity> _dbset;
    public GenericRepository(TDbContext context)
    {
        // need to get updated context here, but getting the initial one
        _context = context;
        _dbset = _context.Set<TEntity>();
    }
}

在Startup.cs中调用的Autofac模块:

builder.Register(a => new ClientDbContext()).InstancePerLifetimeScope();

builder.RegisterGeneric(typeof(GenericRepository<,>)).As(typeof(IGenericRepository<,>)).InstancePerLifetimeScope();

//Register Unit of Work here
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope().PropertiesAutowired();                

//Register Services here
builder.RegisterType<SomeService>().As<ISomeService>().InstancePerLifetimeScope();

任何人都可以帮助我达到上述要求吗?

有什么方法可以使Autofac使用新创建的dbcontext对象?

1 个答案:

答案 0 :(得分:0)

代替

builder.Register(a => new ClientDbContext()).InstancePerLifetimeScope();

您可以使用

builder.Register(c => c.Resolve<IUnitOfWork>().ClientDbContext)
       .InstancePerLifetimeScope(); 

顺便说一句,我不确定您的IUnitOfWork的责任是什么。做到这一点的另一种方法是拥有一个可以提供有关当前用户信息的类:

public interface IClientContext 
{
    public String ClientIdentifier { get; }
}

然后创建一个DbContextFactory,它将基于DbContext

IClientContext

public interface IDbContextFactory { IDbContext CreateDbContext(); } public class DbContextFactory { public DbContextFactory(IClientContext clientContext) { this._clientContext = clientContext; } private readonly IClientContext _clientContext; public IDbContext CreateDbContext() { // get the connectionstring from IClientContext and return the IDbContext } } 的具体实现取决于您获取此信息的方式,它可以来自当前的IClientContext或由您决定的其他任何方式。 似乎在某个时候调用HttpContext可以通过创建SetDbContext来保持这种方式,其中XXXClientContextProvider与获取信息的方式有关。

XXX

然后注册所有类似的内容:

public class XXXClientContextProvider 
{
    private IClientContext _clientContext; 

    public IClientContext GetClientContext()
    {
        if(this._clientContext == null) 
        {
           throw new Exception("client context is null. You should do X or Y"); 
        }
        return this._clientContext; 
    }
    public void SetClientContext(String clientId) 
    {
        if(this._clientContext != null) 
        {
            throw new Exception("client context has already been set"); 
        }
        this._clientContext = new StaticClientContext(clientId);
    }
}