C# 如何使用Autofac将动态DbContext对象注入存储库
我有一个.NETCoreWebAPI应用程序,其中我使用的是实体框架核心和服务层、工作单元和存储库层模式。对于DI,我使用Autofac 应用程序有多个客户端,每个客户端都有自己的数据库,所有这些数据库的模式都是相同的。通过每个API调用,我将获得特定于客户端的连接字符串,使用该字符串我必须创建一个DbContext并将其用于所有操作 在启动类中,我注册了我的dbcontext ClientDbContext和所有其他类。调用工作单元类时,我正在基于连接字符串创建新的DbContext。我希望存储库使用此实例,但存储库仍在使用启动时创建的初始ClientDbContext实例 如何使存储库使用新的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。我希望存
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。但我很高兴