簡體   English   中英

如何使用Autofac將動態DbContext對象注入存儲庫

[英]How to inject dynamic DbContext object into repository using Autofac

我有一個.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對象?

代替

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

你可以用

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

順便說一下,我不確定IUnitOfWork的責任是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);
    }
}

然后像這樣注冊所有內容:

builder.Register(c => c.Resolve<IClientContextProvider>().GetClientContext())
       .As<IClientContext>()
       .InstancePerLifetime(); 

builder.Register(c => c.Resolve<IDbContextFactory>().CreateDbContext())
       .As<IDbContext>()
       .InstancePerLifetime(); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM