Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用Autofac将动态DbContext对象注入存储库_C#_Entity Framework_Dependency Injection_Autofac_Unit Of Work - Fatal编程技术网

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

C# 如何使用Autofac将动态DbContext对象注入存储库,c#,entity-framework,dependency-injection,autofac,unit-of-work,C#,Entity Framework,Dependency Injection,Autofac,Unit Of Work,我有一个.NETCoreWebAPI应用程序,其中我使用的是实体框架核心和服务层、工作单元和存储库层模式。对于DI,我使用Autofac 应用程序有多个客户端,每个客户端都有自己的数据库,所有这些数据库的模式都是相同的。通过每个API调用,我将获得特定于客户端的连接字符串,使用该字符串我必须创建一个DbContext并将其用于所有操作 在启动类中,我注册了我的dbcontext ClientDbContext和所有其他类。调用工作单元类时,我正在基于连接字符串创建新的DbContext。我希望存

我有一个.NETCoreWebAPI应用程序,其中我使用的是实体框架核心和服务层、工作单元和存储库层模式。对于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; }
}
公共类UnitOfWork:IUnitOfWork
{
public ClientDbContext ClientDbContext{get;private set;}
公共工作单元()
{            
}
public void SetDbContext(字符串连接字符串)
{
if(ClientDbContext==null)
{
//在此处创建新的db上下文实例
ClientDbContext=MembershipRepository.CreateDbContext(connectionString);
}                
}        
//属性注入
公共IGenericRepository sometentityGenericRepository{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>();
    }
}
公共类GenericRepository:IGenericRepository其中tenty:class
其中TDbContext:DbContext
{
专用只读TDbContext\u上下文;
私有只读数据库集_DbSet;
公共通用存储库(TDbContext上下文)
{
//需要在这里更新上下文,但要获取初始上下文
_上下文=上下文;
_dbset=_context.Set();
}
}
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();
builder.Register(a=>newclientdbcontext()).InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(GenericRepository)).As(typeof(IGenericRepository)).InstancePerLifetimeScope();
//在这里登记工作单位
builder.RegisterType().As().InstancePerLifetimeScope().PropertiesAutowired();
//在这里注册服务
builder.RegisterType();
有谁能帮我达到以上要求吗

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

而不是

builder.Register(a => new ClientDbContext()).InstancePerLifetimeScope();
你可以用

builder.Register(c => c.Resolve<IUnitOfWork>().ClientDbContext)
       .InstancePerLifetimeScope(); 
然后是一个
DbContextFactory
,它将基于
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(); 
builder.Register(c=>c.Resolve().GetClientContext())
.As()
.InstancePerLifetime();
builder.Register(c=>c.Resolve().CreateDbContext())
.As()
.InstancePerLifetime();
而不是

builder.Register(a => new ClientDbContext()).InstancePerLifetimeScope();
你可以用

builder.Register(c => c.Resolve<IUnitOfWork>().ClientDbContext)
       .InstancePerLifetimeScope(); 
然后是一个
DbContextFactory
,它将基于
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(); 
builder.Register(c=>c.Resolve().GetClientContext())
.As()
.InstancePerLifetime();
builder.Register(c=>c.Resolve().CreateDbContext())
.As()
.InstancePerLifetime();

问题和解决方案可能都是在启动时注册这些依赖项的。你能证明一下吗?@ScottHannen我已经用启动更新了我的问题。实际上,我使用的是我正在启动中注册的Autofac模块。我已经给出了模块的代码。如果你还需要什么,请告诉我。谢谢。每次API调用我都会得到特定于客户端的连接字符串。如何获得这些字符串?如何从请求中识别应该获取的字符串?在查找多租户模式时,您可能会找到所需内容。@GertArnold在每次API调用中,我将获取客户端Id,并使用该Id调用成员资格存储库以获取conn字符串并创建新的db上下文。问题和解决方案可能都是在您注册这些依赖项的启动时出现的。你能证明一下吗?@ScottHannen我已经用启动更新了我的问题。实际上,我使用的是我正在启动中注册的Autofac模块。我已经给出了模块的代码。如果你还需要什么,请告诉我。谢谢。每次API调用我都会得到特定于客户端的连接字符串。如何获得这些字符串?如何从请求中识别应该获取的字符串?在查找多租户模式时,您可能会找到所需内容。@GertArnold在每次API调用中,我将获取客户端Id,并使用该Id调用成员资格存储库以获取conn字符串并创建新的db上下文。这种方法不适用于我的情况,因为在启动中进行Autofac注册时,我将没有客户端Id。我将通过每个api调用接收clientId,然后我需要以某种方式告诉autofac使用我使用clientId创建的新dbcontext覆盖初始dbcontext。但我很高兴