Asp.net core Autofac:ITenantIdentificationStrategy与RouteValue

Asp.net core Autofac:ITenantIdentificationStrategy与RouteValue,asp.net-core,autofac,multi-tenant,asp.net-core-3.1,Asp.net Core,Autofac,Multi Tenant,Asp.net Core 3.1,我在多租户的工作中遇到了问题。我试着遵循示例,但看不出我的实现有什么不同 租户由地址字段中的路由参数标识。调用tryiIdentityEnablent返回正确的值似乎没有问题。我正在使用ASP.NET Core 3.1、Autofac.AspNetCore-Multitenant v3.0.1和Autofac.Extensions.DependencyInjection v6.0.0 我已经对代码进行了简化,该代码已经过测试,但仍然不起作用。配置了两个租户terminal1和terminal2。

我在多租户的工作中遇到了问题。我试着遵循示例,但看不出我的实现有什么不同

租户由地址字段中的路由参数标识。调用tryiIdentityEnablent返回正确的值似乎没有问题。我正在使用ASP.NET Core 3.1、Autofac.AspNetCore-Multitenant v3.0.1和Autofac.Extensions.DependencyInjection v6.0.0

我已经对代码进行了简化,该代码已经过测试,但仍然不起作用。配置了两个租户terminal1和terminal2。根据租户的不同,输出应该有所不同。但是,它总是返回基本实现。在下面的示例中,输入返回base:terminal1并返回base:terminal2。它应该返回userhandler1:terminal1和userhandler2:terminal2

家庭控制器:

公共类HomeController:控制器 { 私有只读IUserHandler userHandler; 私有只读TerminalResolverStrategy TerminalResolverStrategy; 公共HomeControllerIUserHandler用户Handler,TerminalResolverStrategy TerminalResolverStrategy { this.userHandler=userHandler; this.terminalResolverStrategy=terminalResolverStrategy; } 公共字符串索引 { terminalResolverStrategy.tryiIdentificationNantOut对象租户; 返回userHandler.ControllingVncUser+:+stringtenant; } } 用户处理程序:

公共接口IUserHandler { 公共字符串控制vncuser{get;set;} } 公共类UserHandler:IUserHandler { 公共用户处理程序 { 控制VNCUSER=基础; } 公共字符串控制vncuser{get;set;} } 公共类UserHandler1:IUserHandler { 公共用户句柄1 { ControllingVncUser=userhandler1; } 公共字符串控制vncuser{get;set;} } 公共类UserHandler2:IUserHandler { 公共用户句柄2 { ControllingVncUser=userhandler2; } 公共字符串控制vncuser{get;set;} } 启动:

公共StartupI配置 { 配置=配置; } 公共IConfiguration配置{get;} 公共无效配置服务服务服务收集服务 { services.AddHttpContextAccessor; services.addcontrollerswithview; services.addAutoFacMultitenaRequestServices; } 公共无效配置ContainerContainerBuilder生成器 { builder.RegisterType; builder.RegisterType.As; } 公共静态多租户容器配置多租户容器容器容器 { var策略=新的终端解析策略 容器,解决, 容器。解决; var mtc=新的多租户集装箱策略,集装箱; mtc.configuretenanterMinaL1,b=>b.RegisterType.As; mtc.configuretenatorminali2,b=>b.RegisterType.As; 返回mtc; } public void ConfigureIApplicationBuilder应用程序、IWebHostEnvironment环境、iLogger工厂 { 如果环境发展 { app.usedeveloperception页面; app.UseDatabaseErrorPage; } 其他的 { app.UseExceptionHandler/Home/Error; app.UseHsts; } loggerFactory.AddLog4Net; app.UseHttpsRedirection; app.UseStaticFiles; app.UseRouting; app.UseEndpointsendpoints=> { endpoints.MapControllerRoute 名称:默认值, 模式:{terminal}/{controller=Home}/{action=Index}/{id?}; }; } } 节目:

公共课程 { 公共静态无效字符串[]args { CreateHostBuilderargs.Build.Run; } 公共静态IHostBuilder CreateHostBuilderstring[]args=> Host.CreateDefaultBuilderargs .UseServiceProviderFactorynew AutofacMultitenantServiceProviderFactoryStartup.ConfigureMultitenantContainer .ConfigureWebHostDefaultswebBuilder=> { webBuilder.UseStartup; }; } IT身份识别策略:

公共类终端解析策略:ITenantIdentifications策略 { 公共IHttpContextAccessor访问器{get;private set;} 专用只读终端应用设置; 公共终端解析策略 选项, IHttpContextAccessor httpContextAccessor { 访问器=httpContextAccessor; 设置=选项。值; } 公共bool tryiIdentificationOut对象终端 { HttpContext httpCtx=Accessor.HttpContext// 终端=空; 尝试 { 如果httpCtx!=null&& httpCtx.Request!=null&& httpCtx.Request.RouteValues!=null&& httpCtx.Request.RouteValues.containsByTerminal { string requestedTerminal=httpCtx.Request.RouteValues[terminal].ToString; bool terminalExists=settings.Terminals.ContainsKeyrequestedTerminal; 如果是语言学家 { 终端=请求的终端; } } } 捕获异常{} 返回终端!=null; } } }
我做错了什么?提前感谢。

多租户似乎根本不起作用,这是一个有点模棱两可的说法,很难解决。不幸的是,我个人没有时间下载您所有的示例代码,并尝试重新编译整个过程并调试到其中,以查看到底出了什么问题。也许其他人会。不过,我可以提供一些建议,比如我会去哪里看,以及我会尝试去看什么

租户ID策略设置两次。我在Startup.ConfigureContainer中看到一个builder.RegisterType;行-这将把您的策略类型注册为每个依赖项的实例,所以每次需要它时,它都会被重新解析。在Startup.ConfigureMultitenantContainer中,我还看到您正在手动实例化multitenant容器使用的策略。有一种非零的可能性,那就是有什么东西被搞砸了。我会选择一种方法来完成这项工作——要么注册策略,要么手动创建它——我会确保这是一个无状态的单例。示例中没有注册它

路线模式可能有问题。我看到您注册的路由模式如下:{terminal}/{controller=Home}/{action=Index}/{id?}。我还看到您的URL如下所示:https://localhost/app/terminal1 您是否已加入租户ID策略以确保路由解析机制正常工作?也就是说,应用程序没有被选为终值?路由解析/处理可能很棘手

可能是坏的设置。只有当存在指定特定终端值存在的选项时,租户ID策略才能成功标识租户。我看不到这些选项在哪里配置,这意味着在回购协议中没有定义租户。如果没有这些,你的策略将无法识别任何东西

如果是我,我可能会从租户ID策略中的一个断点开始,看看解决了什么问题,没有解决什么问题。从外部的角度看,这似乎有点复杂,这就是我要开始的地方。如果这是可行的,那么我可能还会考虑清理注册,这样ID策略就不会注册两次。最后,我得到的印象是,这并不是应用程序中的全部代码;我可能会考虑制作一个超小的复制品,这个复制品的大小和你在这里发布的尺寸差不多。然后,我会专注于使最小的复制工作;然后,一旦它工作,我就会找出复制和我的更大的应用程序之间的区别


不幸的是,我只能给你这么多了。正如我提到的,在当前的环境和工作负载下,我无法坐下来用您的代码重现整个过程。我知道集成是有效的,因为我有使用它的生产应用程序;有大量的单元测试和集成来验证它的有效性;因此,不起作用的部分可能在代码的某个地方。。。这些就是我要开始的地方。

因此,在确定租户标识是问题之后,似乎直到稍后在请求链中才使用HttpContext解决RouteValue。因此,没有租户得到解决。在我看来,它就像.NET内核中的一个bug。改为使用请求路径绕过了该问题:

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

您是否尝试过不制作自定义多租户容器?在配置MultitenantContainer中,什么已满?你有没有尝试过在没有额外的非标准配置设置的情况下简化事情,让基础工作起来?请更新问题,不要把这些东西都放在这里的评论中。@TravisIllig我现在意识到多租户似乎根本不起作用。我已经更新并澄清了示例。。。我真的看不出我与github上的示例有什么不同。感谢您的回复。至少它让我确信这不是什么明显的事情。正如您所怀疑的,是租户ID策略有问题。把答案贴在下面。