【问题标题】:How to inject IHttpContextAccessor into Autofac TenantIdentificationStrategy如何将 IHttpContextAccessor 注入 Autofac TenantIdentificationStrategy
【发布时间】:2016-11-01 20:38:06
【问题描述】:

我正在将我的多租户应用程序从 Webapi 迁移到 aspnet 核心。在 webapi 版本中,我使用的是 TenantIdentificationStrategy,它根据 HttpContext 上的请求路径识别租户。

转移到 aspnet 核心,我能够成功连接 autofac。我无法弄清楚如何连接租户策略。我尝试在ConfigureServices 中注入IHttpContextAccessor

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 

我的策略是这样的

public class AssetClassIdentificationStrategy: ITenantIdentificationStrategy {
    private readonly IHttpContextAccessor _accessor;
    public AssetClassIdentificationStrategy(IHttpContextAccessor httpContextAccessor)
    {
        _accessor = httpContextAccessor;
    }
    public bool TryIdentifyTenant(out object tenantId) {
        tenantId = null;
        var context = _accessor.HttpContext;
        if (context != null && context.Request != null )){
            var matchRegex = new Regex(@"\/[\d,\.,\w]*\/(\w*)\/.*");
            var match = matchRegex.Match(context.Request.Path.ToString());
            if (match.Success) {
                tenantId = match.Groups[1].Value.ToLower();
            }
        }
        return tenantId != null;
    }
}

我看到的是HttpContextAccessor 被正确注入,其中HttpContext 始终为空。因此,没有解决任何多租户服务。

四处寻找样本,但找不到适合问题的任何东西。 Autofacv3 中曾经有一个 RequestParameterTenantIdentificationStrategy,它不再受支持。感谢您对此的任何帮助。

编辑 修复了代码问题并按要求添加 Startup.cs。

public class Startup
{
    public Startup(IHostingEnvironment env) {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.Configure<CacheConfig>(Configuration.GetSection("Caching"),false);
        services.AddMvc();
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddTransient<ITenantIdentificationStrategy,AssetClassIdentificationStrategy>();

        var builder = new ContainerBuilder();
        builder.Populate(services);
        builder.RegisterType<TenantInfo>().WithProperty("TenantName", "unknown").As<ITenantInfo>();

        var container = builder.Build();

        ITenantIdentificationStrategy tenantIdentificationStrategy;
        bool isMultiTenant = container.TryResolve(out tenantIdentificationStrategy);

        var mtc = new MultitenantContainer(tenantIdentificationStrategy, container);
        mtc.ConfigureTenant("pesonalLoans", b => {
            b.RegisterType<TenantInfo>().WithProperty("TenantName","pesonalLoans") .As<ITenantInfo>();
        });
        mtc.ConfigureTenant("retirement", b => {
            b.RegisterType<TenantInfo>().WithProperty("TenantName", "retirement").As<ITenantInfo>();
        });

        return mtc.Resolve<IServiceProvider>();

    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        LoggingConfig.Register(Configuration, loggerFactory);
        app.UseMvc();
    }
}


public class ValuesController : Controller {
    private ITenantInfo _tenant;
    public ValuesController(ITenantInfo tenant) {
        _tenant = tenant;
    }

    [HttpGet]
    public string Get()
    {
        return  _tenant.TenantName;
    }
}


public interface ITenantInfo {
    string TenantName { get; set; }
}
public class TenantInfo: ITenantInfo
{
    public string TenantName { get; set; }
}

编辑 3 project.json

{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.0.0-rc2-3002702",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging.Debug": "1.0.0-rc2-final",
    "Autofac": "4.0.0-rc2-240",
    "Autofac.Multitenant": "4.0.0-beta8-219",
    "System.IdentityModel.Tokens.Jwt": "5.0.0-rc2-305061149",
    "Autofac.Extensions.DependencyInjection": "4.0.0-rc2-240",
    "System.Reflection": "4.1.0-rc2-24027",
    "System.Reflection.Primitives": "4.0.1-rc2-24027",
    "System.Reflection.Extensions": "4.0.1-rc2-24027",
    "System.Reflection.TypeExtensions": "4.1.0-rc2-24027",
    "System.Reflection.Emit": "4.0.1-rc2-24027",
    "System.Reflection.Context": "4.0.1-rc2-24027",
    "System.Reflection.DispatchProxy": "4.0.1-rc2-24027",
    "System.Reflection.Emit.ILGeneration": "4.0.1-rc2-24027",
    "Microsoft.AspNetCore.Diagnostics": "1.0.0-rc2-final",
    "Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-rc1-final",
    "Microsoft.AspNet.Mvc.Formatters.Json": "6.0.0-rc1-final",
  },

  "tools": {
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": "portable-net45+win8+dnxcore50"
    }
  },

  "frameworks": {
    "netcoreapp1.0": {
      "imports": [
        "dotnet5.6",
        "dnxcore50",
        "portable-net45+win8"
      ]
    }
  },

  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

  "runtimeOptions": {
    "gcServer": true
  },

  "scripts": {
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}

【问题讨论】:

  • 你能发布你的启动文件吗?
  • 我已附上启动文件

标签: c# asp.net-core autofac multi-tenant asp.net-core-1.0


【解决方案1】:

这变得太渴望评论了。

首先你的类被命名为SampleIdentificationStrategy,但你的构造函数引用了AssetClassIdentificationStrategy。从这个问题开始,项目甚至不应该编译。

接下来(因为您没有提供启动文件)确保通过在 ConfigureServices 方法中调用以下代码来填充 AutoFac 中的注册服务。

builder.Populate(services);
builder.Update(container);

注意此方法必须在您将所有服务注册到IServiceCollection

之后运行

接下来确保您没有混合框架版本。 RC2 RC1beta-x 等之间存在很大差异。这在 GitHub 问题日志中注明了 herehere

除此之外,我们还需要查看您的 startup.cs 文件(特别是从 ConfigureServices 方法中提取的文件、您的 project.json 文件(特别是 frameworksdependency 节点)。

【讨论】:

  • 我添加了statup文件和project.json,请看一下
【解决方案2】:

目前没有办法将事物注入租户识别策略,因为该策略本身不通过 DI 管道。

IHttpContextAccessor 通常只支持HttpContextAccessor,无论如何它都是一个单例,并且通过从异步/线程本地上下文获取信息来执行操作。您可以在刚开始时直接使用其中一种来更新您的策略:

var strat = new MyStrategy(new HttpContextAccessor());

请注意,在最初提出问题时,多租户与 ASP.NET Core IServiceProvider 系统的交互方式存在问题,也就是说,它没有。

从那时起,我们发布了 4.0.0-rc3-309 for the Autofac.Extensions.DependencyInjection package 来解决这个问题。

变化是您需要将ConfigureServices更新为return new AutofacServiceProvider(mtc);,不再使用return mtc.Resolve&lt;IServiceProvider&gt;();

【讨论】:

  • 我现在尝试了这种方法,我发现 HttpContextAccessor 中的 HttoContext 为空。我发现的另一件事是,如果我在策略中的 TryIdentifyTenant 中放置一个断点,则断点不会针对每个请求的页面命中。任何想法我做错了什么?
  • 我还没有亲自尝试过支持多租户的新 ASP.NET Core 东西。我不确定那里有什么,但当前的核心集成很可能正在做一些绕过多租户的事情。我得去看看。不过,上下文访问器应该可以工作。
  • 我已经为整个 Autofac to do list for Core 添加了评论。我们会看看它。
  • 已在最新版本中修复。相应地更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 2017-01-01
  • 2019-12-01
  • 1970-01-01
  • 2022-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-01
相关资源
最近更新 更多