Autofa c: стратегия ITenantIdentification со значениями RouteValues - PullRequest
0 голосов
/ 09 апреля 2020

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

Арендаторы идентифицируются параметром маршрутизации в поле адреса. Кажется, это работает без проблем (вызов TryIdentifyTenant возвращает правильный). Я использую ASP. NET Core 3.1 вместе с Autofa c .AspNetCore-Multitenant v3.0.1 и Autofa c .Extensions.DependencyInjection v6.0.0.

Я сделал упрощение кода (который проверен и до сих пор не работает). Два арендатора настроены, «терминал1» и «терминал2». Выход должен отличаться в зависимости от арендатора. Тем не менее, он всегда возвращает базовую реализацию. В приведенном ниже примере ввод «https://localhost/app/terminal1» возвращает «base: терминал1», а «https://localhost/app/terminal2» возвращает «base: терминал2». Он должен возвращать «userhandler1: терминал1» и «userhandler2: терминал2».

HomeController:

     public class HomeController : Controller
    {
        private readonly IUserHandler userHandler;
        private readonly TerminalResolverStrategy terminalResolverStrategy;

        public HomeController(IUserHandler userHandler, TerminalResolverStrategy terminalResolverStrategy)
        {
            this.userHandler = userHandler;
            this.terminalResolverStrategy = terminalResolverStrategy;
        }

        public string Index()
        {
            terminalResolverStrategy.TryIdentifyTenant(out object tenant);
            return userHandler.ControllingVncUser + " : " + (string)tenant;
        }
    }

UserHandler:

public interface IUserHandler
    {
        public string ControllingVncUser { get; set; }
    }

    public class UserHandler : IUserHandler
    {
        public UserHandler()
        {
            ControllingVncUser = "base";
        }

        public string ControllingVncUser { get; set; }
    }


    public class UserHandler1 : IUserHandler
    {
        public UserHandler1()
        {
            ControllingVncUser = "userhandler1";
        }

        public string ControllingVncUser { get; set; }
    }

    public class UserHandler2 : IUserHandler
    {
        public UserHandler2()
        {
            ControllingVncUser = "userhandler2";
        }

        public string ControllingVncUser { get; set; }
    }

Запуск:

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

        public IConfiguration Configuration { get; }

           public void ConfigureServices(IServiceCollection services)
        {

            services.AddHttpContextAccessor();

            services.AddControllersWithViews();
            services.AddAutofacMultitenantRequestServices();
        }

        public void ConfigureContainer(ContainerBuilder builder)
        {
            builder.RegisterType<TerminalResolverStrategy>();
            builder.RegisterType<UserHandler>().As<IUserHandler>();
        }

        public static MultitenantContainer ConfigureMultitenantContainer(IContainer container)
        {
            var strategy = new TerminalResolverStrategy(
                container.Resolve<IOptions<TerminalAppSettings>>(), 
                container.Resolve<IHttpContextAccessor>());

            var mtc = new MultitenantContainer(strategy, container);

            mtc.ConfigureTenant("terminal1", b => b.RegisterType<UserHandler1>().As<IUserHandler>());
            mtc.ConfigureTenant("terminal2", b => b.RegisterType<UserHandler2>().As<IUserHandler>());

            return mtc;
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            loggerFactory.AddLog4Net();

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();


            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{terminal}/{controller=Home}/{action=Index}/{id?}");
            });
        }
}

Программа:

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

ITenantIdentificationStrategy:

        public class TerminalResolverStrategy : ITenantIdentificationStrategy
    {
        public IHttpContextAccessor Accessor { get; private set; }

        private readonly TerminalAppSettings settings;

        public TerminalResolverStrategy(
            IOptions<TerminalAppSettings> options,
            IHttpContextAccessor httpContextAccessor
            )
        {
            Accessor = httpContextAccessor;
            settings = options.Value;
        }

        public bool TryIdentifyTenant(out object terminal)
        {
            HttpContext httpCtx = Accessor.HttpContext;//
            terminal = null;
            try
            {
                if (httpCtx != null &&
                    httpCtx.Request != null &&
                    httpCtx.Request.RouteValues != null &&
                    httpCtx.Request.RouteValues.ContainsKey("terminal"))
                {
                    string requestedTerminal = httpCtx.Request.RouteValues["terminal"].ToString();
                    bool terminalExists = settings.Terminals.ContainsKey(requestedTerminal);
                    if (terminalExists)
                    {
                        terminal = requestedTerminal;
                    }
                }
            }
            catch (Exception) {}
            return terminal != null;
        }
    }
}

Что я делаю не так? Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 10 апреля 2020

«Многопрофильность, похоже, совсем не работает» - это довольно неоднозначное утверждение, которое трудно рассмотреть. К сожалению, у меня лично нет времени, чтобы загрузить весь ваш пример кода и попытаться воспроизвести все это, отладить его и посмотреть, что именно не так. Возможно, кто-то еще. Тем не менее, я могу предложить несколько советов относительно мест, которые я посмотрю, и вещей, которые я попытаюсь увидеть, в чем дело.

Стратегия идентификации арендатора настроена дважды. Я вижу в Startup.ConfigureContainer что есть строка builder.RegisterType<TerminalResolverStrategy>(); - она ​​будет регистрировать тип вашей стратегии как экземпляр-на-зависимость, поэтому каждый раз, когда это необходимо, она разрешается для fre sh. Я также вижу в Startup.ConfigureMultitenantContainer, что вы вручную создаете экземпляр стратегии, которая используется контейнером с несколькими арендаторами. Существует ненулевая вероятность того, что что-то там запуталось. Я бы выбрал один из способов сделать это - либо зарегистрировать стратегию, либо создать ее вручную - и я бы удостоверился, что это одноэлементный файл без сохранения состояния. (Это не зарегистрировано в примере.)

Возможно, сомнительный шаблон маршрута. Я вижу зарегистрированный шаблон маршрута выглядит следующим образом: {terminal}/{controller=Home}/{action=Index}/{id?}. Я также вижу, что ваши URL-адреса выглядят так: https://localhost/app/terminal1 Вступили ли вы в свою стратегию идентификации арендатора, чтобы убедиться, что механизм разбора маршрута работает правильно? То есть app не принимается за значение terminal? Синтаксический анализ / обработка маршрута может быть сложным.

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

Если бы это был я, я бы, вероятно, начал с точки останова в этой стратегии идентификации арендатора и посмотрел, что решается, а что нет. Это кажется несколько сложным с внешней точки зрения, и именно здесь я начну. Если это сработает, то я, вероятно, также рассмотрю вопрос очистки регистраций, чтобы стратегия идентификации не регистрировалась дважды. Наконец, у меня сложилось впечатление, что это не весь код в приложении; Я бы, наверное, посмотрел на создание супер минимального репродукции размером примерно с тот, который вы на самом деле разместили здесь. Затем я бы сосредоточился на том, чтобы заставить это минимальное репро работать; затем, как только это сработает, я выясню, в чем разница между репро и моим большим приложением.

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

0 голосов
/ 11 апреля 2020

Таким образом, после определения идентификации арендатора как проблемы, кажется, что RouteValues ​​не решается с помощью HttpContext до тех пор, пока в цепочке запросов не будет найдено. Таким образом, ни один арендатор не будет решен. Мне кажется, что это ошибка в. NET Core. Проблема была обойдена путем использования пути запроса:

public class TerminalResolverStrategy : ITenantIdentificationStrategy
{

    private readonly TerminalAppSettings settings;
    private readonly IHttpContextAccessor httpContextAccessor;

    public TerminalResolverStrategy(
        IOptions<TerminalAppSettings> options,
        IHttpContextAccessor httpContextAccessor
        )
    {
        this.httpContextAccessor = httpContextAccessor;
        settings = options.Value;
    }

    public bool TryIdentifyTenant(out object terminal)
    {
        var httpCtx = httpContextAccessor.HttpContext;
        terminal = null;
        try
        {
            if (httpCtx != null)
            {
                string thisPath = httpCtx.Request.Path.Value;
                var allTerminals = settings.Terminals.GetEnumerator();
                while (allTerminals.MoveNext())
                {
                    if (thisPath.Contains(allTerminals.Current.Key)) { 
                    terminal = allTerminals.Current.Key;
                    return true;
                    }
                }
            }
        }
        catch (Exception) { }
        return false;
    }
}
...