Как добавить динамический объект DbContext в хранилище с помощью Autofac - PullRequest
0 голосов
/ 11 июля 2019

У меня есть приложение .net core web api, где я использую ядро ​​Entity Framework с сервисным уровнем, единицей работы и шаблоном уровня хранилища.Для DI я использую Autofac.

Приложение имеет несколько клиентов и каждый клиент имеет свою собственную базу данных , и схема для всех этих баз данных одинакова. При каждом вызове API я получаю строку подключения, специфичную для клиента, с помощью которой мне приходится создавать DbContext и использовать его для всех его операций.

В классе запуска я зарегистрировал свой dbcontextClientDbContext и все другие классы.Когда вызывается класс единицы работы, я создаю свой новый 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:

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 голосов
/ 12 июля 2019

вместо

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);
    }
}

и затем зарегистрируйте все так:

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

builder.Register(c => c.Resolve<IDbContextFactory>().CreateDbContext())
       .As<IDbContext>()
       .InstancePerLifetime(); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...