asp. net ядро ​​3.1 объединяет автофо c с проушиной - PullRequest
2 голосов
/ 06 апреля 2020

Я создаю мультитенантное приложение asp. net core 3.1 с несколькими базами данных (по одной на каждого арендатора и одну основную базу данных). Я использую Autofa c для поддержки времени жизни Singleton на каждого арендатора для моих услуг (сейчас мне не нужно переопределение арендатора, мне нужно только настраиваемое время жизни SinglePerTenant) Я использую

My Стратегия идентификации арендатора включает вызов базы данных в базу данных master.

Как написано в документации autofa c, стратегия идентификации не должна иметь обращений к базе данных, поскольку она вызывается при каждом разрешении зависимости. Затем я использовал другое решение для идентификации арендатора (Finbuckle.MultiTenant).

В Finbukle, когда приходит запрос, вызывается его стратегия идентификации (один раз на запрос htp), я помещаю вызов db в его стратегию идентификации (для оптимизации я могу кэшировать результат и повторно обновить sh запрос). день) и объект tenantInfo устанавливается в HttpContext.

Затем В стратегии идентификации AutoFa c я пытаюсь прочитать объект, установленный FinBuckle, но это невозможно, поскольку стратегия идентификации Autofa c вызывается перед единицами FinBuckle, и свойство desidered имеет значение null.

Мои Program.cs:

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
        .UseServiceProviderFactory(new AutofacMultitenantServiceProviderFactory(Startup.ConfigureMultitenantContainer))
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Startup.cs:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMultiTenant().WithStrategy<TestStategy>(ServiceLifetime.Singleton).WithStore<CustomTestStore>(ServiceLifetime.Singleton); //enable the multitenant support from finbukle

        services.AddControllers();

        services.AddAutofacMultitenantRequestServices();

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

        app.UseMultiTenant() //finbukle

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }

    public void ConfigureContainer(ContainerBuilder builder)
    {
         builder.RegisterType<TestDiA>().As<ITestDI>().InstancePerTenant();
    }

    public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
    {
        // This is the MULTITENANT PART. Set up your tenant-specific stuff here.
        var strategy = new MyAutofacTenantIdentificationStrategy(container.Resolve<IHttpContextAccessor>());
        var mtc = new MultitenantContainer(strategy, container);
        return mtc;
    }
}

Autofa c стратегия идентификации арендатора:

public class MyAutofacTenantIdentificationStrategy : ITenantIdentificationStrategy
{
    private readonly IHttpContextAccessor httpContextAccessor;
    public MyAutofacTenantIdentificationStrategy(
      IHttpContextAccessor httpContextAccessor
    )
    {
        this.httpContextAccessor = httpContextAccessor;
    }
    public bool TryIdentifyTenant(out object tenantId)
    {
        tenantId = null;
        var context = httpContextAccessor.HttpContext;
        if (context == null)
            return false;


        var identifier = context.getTenatInfo()?.Identifier ?? null; //getTenantInfo is a method that extract the tenant info object setted by finbukle
        tenantId = identifier;
        return (tenantId != null || tenantId == (object)"");
    }
}

Я использую Autofa c .AspNetCore.Multitenant 3.0.0, Autofa c .Extensions.DependencyInjection 6.0.0 и FinBuckle.MultiTenant 5.0.4

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

Или для моего выпуска есть альтернативная стратегия?

1 Ответ

3 голосов
/ 07 апреля 2020

В настоящее время я не верю, что Finbuckle и Autofa c .Multitenant совместимы.

Autofa c Поддержка нескольких арендаторов для ASP. NET Core зависит от запуска первым вещь в конвейере промежуточного программного обеспечения, поэтому он может установить HttpContext.RequestServices в соответствии с областью действия арендатора . Как часть этого, конечно, стратегия идентификации арендаторов будет работать.

Однако Finbuckle предполагает, что каждый арендатор совместно использует контейнер , как по умолчанию ASP. NET Core функциональность. Промежуточное программное обеспечение Finbuckle пытается использовать HttpContext.RequestServices для идентификации арендатора на основе зарегистрированных стратегий .

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

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

Если вы погрузитесь в код Finbuckle, промежуточное ПО устанавливает информацию об арендаторе на HttpContext.Items как часть их работы промежуточного ПО. Позже, когда вы извлекаете информацию об арендаторе, она извлекается из HttpContext.Items, а не повторно разрешается через базу данных . Вызов базы данных выполняется только один раз, при первом запуске ИД арендатора.

Это, вероятно, хорошо. В зависимости от того, сколько арендаторов вы планируете поддерживать и как часто они меняются, может быть, стоит добавить какой-нибудь слой кэширования в памяти, который вы можете использовать для хранения данных идентификатора арендатора (все, что хранится в базе данных, помогает идентифицировать этого арендатора). так что вы можете попробовать в хранилище в памяти, прежде чем попасть в базу данных. Может быть, там периодически истекает срок действия данных, или же это фиксированный размер, или что-то в этом роде ... стратегия кэширования полностью зависит от приложения, и я никак не мог бы порекомендовать какие-либо особенности в этом отношении. Суть в том, что это один из способов облегчить вызов базы данных.

Но возвращаясь к проблеме курица / яйцо, я не вижу простого способа обойти это.

Если бы это был я и Мне нужно было заставить это работать, я, вероятно, пропустил бы вызов IApplicationBuilder.UseMultiTenant() extension , а затем создал бы свою собственную версию их промежуточного программного обеспечения , которая вместо , используя HttpContext.RequestServices чтобы получить стратегии ID арендатора , должен взять контейнер с несколькими арендаторами прямо в конструкторе, например, мультитенантное промежуточное ПО Autofa c и напрямую использовать контейнер уровня приложения для разрешения этих стратегий . Это, конечно, должно быть запущено до промежуточного программного обеспечения для служб многопользовательских запросов Autofa c, и принудительное выполнение заказа промежуточного программного обеспечения является болезненным . Наконец, поскольку HttpContext.Items в конечном итоге будет иметь идентификацию арендатора после запуска этого промежуточного программного обеспечения, ваша Autofa c ITenantIdentificationStrategy может просто посмотреть туда, чтобы получить данные и вообще не вызывать базу данных.

Однако ...

ОГРОМНЫЙ, ИЗУМИТЕЛЬНО ВАЖНЫЙ ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ

  • Я никогда в жизни не использовал Finbuckle. Я могу просмотреть код на GitHub, но я не знаю, какие побочные эффекты могут иметь вышеуказанные соображения.
  • На самом деле я не пробовал вышеуказанное рассмотрение. Это может не сработать.
  • Я поддерживаю проект Autofa c и написал оригинальную поддержку нескольких арендаторов, включая оригинальную интеграцию с ASP. NET Core. Было очень больно заставить его работать ... поэтому, когда я говорю, что вышеупомянутое соображение может быть хитрым, я был там.
  • Я очень конкретно называю это "рассмотрением" - что-то рассмотреть - и не является рекомендацией , потому что я не собираюсь обязательно «рекомендовать» то, в чем я не очень уверен. У меня нет уверенности, потому что, опять же, я не не использую Finbuckle.

МОЯ АКТУАЛЬНАЯ РЕКОМЕНДАЦИЯ ... ну, немного замедлиться. Как вы упомянули, вы новичок в этой области, и кажется, что материал, с которым вы собираетесь здесь столкнуться, довольно глубокий. Я рекомендую погрузиться в реальный код Finbuckle на GitHub , если вы этого не сделали. Не похоже, что есть много, и это может дать вам некоторое представление о том, что происходит. Я рекомендую попробовать создать мультитенантное приложение с просто Autofa c с несколькими арендаторами и одно с просто Finbuckle. Посмотри, действительно ли тебе нужны оба. Может быть, только один имеет смысл. Например, кажется, что Finbuckle уже имеет многопользовательский режим для хранения данных; это то, для чего многие люди также используют мультитенантность Autofa c - для регистрации различных контекстов базы данных для каждого арендатора. Возможно, было бы достаточно использовать только один из продуктов, и это могло бы устранить всю проблему.

...