Доступ к ядру asp.net dbcontext внутри класса - PullRequest
0 голосов
/ 28 апреля 2018

У меня есть приложение Asp.net core 2, где я настроил dbContext с шаблоном репозитория и единицей работы.

Все работает нормально, я могу получить доступ к UnitOfWork в контроллере и получить данные.

Я пытаюсь получить доступ к контексту в Middleware, а также к классу в другом проекте, но я не знаю, какой из них лучший.

DbContext

public class BloggingContext : DbContext
{
    public BloggingContext(DbContextOptions<BloggingContext> options)
      :base(options)
    { }

    public DbSet<Blog> Blogs { get; set; }
    ...
}

Запуск

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddDbContext<BloggingContext>(options => options.UseMySQL(configuration.GetConnectionString("DefaultDb")));

    services.AddScoped<IBloggingContext, BloggingContext>();
    services.AddTransient<IUnitOfWork, UnitOfWork>();
    ...
}

Middleware

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ...
    app.UseMyMiddleware();
    ...
}

public class MyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IConfiguration _configuration;
    private readonly IMemoryCache _memoryCache;

    public MyMiddleware(RequestDelegate next, IConfiguration configuration, IMemoryCache memoryCache)
    {
        _next = next;
        _configuration = configuration;
        _memoryCache = memoryCache;
    }

    public Task Invoke(HttpContext httpContext)
    {
        ...
        HERE I NEED TO ACCESS DATABASE

        ...
        return _next(httpContext);
    }
}

public static class MyMiddlewareExtensions
{
    public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<MyMiddleware>();
    }
}

Что я делаю внутри функции Invoke:

var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseMySQL(_configuration.GetConnectionString("DefaultDb"));

using (var dbContext = new BloggingContext(optionsBuilder.Options))
{
    var blog = dbContext.Blogs.FirstOrDefault();
    ...
}

Я почти уверен, что это не лучший способ. Также идеальным способом было бы получить доступ, как будто я получаю доступ в контроллере, напрямую к UnitOfWork без, но я не знаю, возможно ли это.

Кроме того, мне нужен доступ к одному и тому же DbCOntext внутри класса в другом проекте, и в этом случае у меня возникает другая проблема: как получить доступ к строке подключения конфигурации, которая находится в appsettings.json моего веб-проекта.

Может ли кто-нибудь помочь мне понять, как это сделать в новом ядре asp.net 2?

Кроме того, если кому-то нужно больше кода, я не против поделиться тем, что у меня есть, если это поможет другим.

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

Ну, это похоже на блог, а не на вопрос переполнения стека ... Я отвечаю на свои вопросы, но если это может помочь только одному человеку ... Это было очень продуктивное воскресенье.

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

IServiceProvider serviceProvider

public class DbContextTenant : IdentityDbContext<ApplicationUser, ApplicationRole, int>, IDbContextTenant
{
    private readonly string _connectionString;

    public DbContextTenant(DbContextOptions<SpzContextClient> options, 
IHttpContextAccessor contextAccessor, IServiceProvider serviceProvider) : base(options)
    {
        var tenantId = (int)contextAccessor.HttpContext.Items["TenantId"];
        _connectionString = contextAccessor.HttpContext.Items["DbString"].ToString();

        TenantInitialization.Initialize(serviceProvider, this, tenantId);
    }

Как видите, я передаю serviceProvider для инициализации базы данных клиентов. Таким образом, я могу использовать основной DbContext при инициализации другого DbCOntext, который обращается ко всем арендаторам.

Инициализация будет примерно такой.

public static void Initialize(IServiceProvider serviceProvider, DbContextTenant context, int tenantId)
{
    if (((RelationalDatabaseCreator) context.GetService<IDatabaseCreator>()).Exists()) return;

    context.Database.EnsureCreated();

    LanguageInitialization.Initialize(context);
    CountryInitialization.Initialize(context);

    using (var DbContext = serviceProvider.GetRequiredService<DbContext>())
    {
        CompanyInitialization.Initialize(context, contextMaster, tenantId);
    }

    context.SaveChanges();
}

Если вы знаете лучший способ сделать это, пожалуйста, дайте мне знать.

Если база данных уже существует, она ничего не делает. Это только первый раз, когда кто-то получает доступ к сайту арендатора, поэтому мы можем просто добавить арендатора в базу данных, и приложение создаст саму базу данных. Таким способом действительно легко создавать новых клиентов (арендаторов), просто добавив строку в таблицу клиентов основной базы данных.

Создает базу данных и инициализирует нужные нам таблицы, такие как языки, страны ... и компанию, получая всю информацию из таблицы Client основного DbContext.

Это мультитенантное приложение, asp.net core 2, единая установка кода, одна основная база данных и одна база данных для каждого арендатора. Каждый арендатор имеет свой домен, поэтому мы используем хост для различия между арендаторами.

У меня было много проблем, чтобы попасть сюда, поэтому я делюсь этим, если кому-то это нужно. Я бы хотел иметь всю информацию, которая у меня есть сейчас. Если у вас есть какие-либо вопросы или вам нужен код, я хотел бы поделиться всем, что вам нужно.

0 голосов
/ 29 апреля 2018

Я нашел решение для MiddleWare, но не для класса в другом проекте.

Вам нужно только внедрить IUnitOfWork в Invoke of Middleware, и он работает.

public class MyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IConfiguration _configuration;
    private readonly IMemoryCache _memoryCache;

    public MyMiddleware(RequestDelegate next, IConfiguration configuration, 
IMemoryCache memoryCache)
    {
        _next = next;
        _configuration = configuration;
       _memoryCache = memoryCache;
    }

    public Task Invoke(HttpContext httpContext, IUnitOfWork unitOfWork) 
    {
        var myData = _unitoOfWork.Blogs.GetFirst();
        ...
        return _next(httpContext);
    }
}

У меня все еще есть проблема вызова DbContext в моем другом DbContext при заполнении базы данных.

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

public class DbContextTenant : IdentityDbContext<ApplicationUser, ApplicationRole, int>, IDbContextTenant
{
    private readonly string _connectionString;

    public DbContextTenant(DbContextOptions<SpzContextClient> options, IHttpContextAccessor contextAccessor) : base(options)
    {
        var tenantId = (int)contextAccessor.HttpContext.Items["TenantId"];
        _connectionString = contextAccessor.HttpContext.Items["DbString"].ToString();

        SEED DATABASE
        HERE IS WHERE I NEED TO CALL THE MAIN DBCONTEXT
    }

Как я могу назвать основной DbCOntext там ???

...