如何将 IHttpContextAccessor 注入 Autofac TenantIdentificationStrategy
How to inject IHttpContextAccessor into Autofac TenantIdentificationStrategy
我正在将我的多租户应用程序从 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
始终为空。因此,none 的多租户服务正在得到解决。
四处寻找示例,但找不到适合问题的内容。 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%" ]
}
}
评论太长了。
首先,您的 class 被命名为 SampleIdentificationStrategy
,但您的构造函数引用了 AssetClassIdentificationStrategy
。从这个问题开始,项目甚至不应该编译。
接下来(因为您还没有提供启动文件)确保通过在 ConfigureServices
方法中调用以下代码来填充 AutoFac 中的注册服务。
builder.Populate(services);
builder.Update(container);
请注意此方法必须 运行 在您已将所有服务注册到 IServiceCollection
接下来确保您没有混用框架版本。 RC2
RC1
、beta-x
等之间存在很大差异。这已在 GitHub 问题日志中注明 here and here。
除此之外,我们还需要查看您的 startup.cs
文件(特别是 ConfigureServices
方法的摘录,您的 project.json
文件(特别是 frameworks
和 dependency
节点).
目前没有办法将东西注入到租户识别策略中,因为该策略本身不通过 DI 管道。
IHttpContextAccessor
通常仅由 HttpContextAccessor
支持,无论如何这是一个单例,并通过从 async/thread 本地上下文获取信息来执行操作。您可以在启动时直接使用其中之一来更新您的策略:
var strat = new MyStrategy(new HttpContextAccessor());
请注意,在最初提出问题时,多租户与 ASP.NET 核心 IServiceProvider
系统交互的方式存在问题,也就是说,它没有。
从那时起,我们发布了 4.0.0-rc3-309
for the Autofac.Extensions.DependencyInjection
package 解决了这个问题。
变化是您需要将ConfigureServices
更新为return new AutofacServiceProvider(mtc);
,不再执行return mtc.Resolve<IServiceProvider>();
。
我正在将我的多租户应用程序从 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
始终为空。因此,none 的多租户服务正在得到解决。
四处寻找示例,但找不到适合问题的内容。 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%" ]
}
}
评论太长了。
首先,您的 class 被命名为 SampleIdentificationStrategy
,但您的构造函数引用了 AssetClassIdentificationStrategy
。从这个问题开始,项目甚至不应该编译。
接下来(因为您还没有提供启动文件)确保通过在 ConfigureServices
方法中调用以下代码来填充 AutoFac 中的注册服务。
builder.Populate(services);
builder.Update(container);
请注意此方法必须 运行 在您已将所有服务注册到 IServiceCollection
接下来确保您没有混用框架版本。 RC2
RC1
、beta-x
等之间存在很大差异。这已在 GitHub 问题日志中注明 here and here。
除此之外,我们还需要查看您的 startup.cs
文件(特别是 ConfigureServices
方法的摘录,您的 project.json
文件(特别是 frameworks
和 dependency
节点).
目前没有办法将东西注入到租户识别策略中,因为该策略本身不通过 DI 管道。
IHttpContextAccessor
通常仅由 HttpContextAccessor
支持,无论如何这是一个单例,并通过从 async/thread 本地上下文获取信息来执行操作。您可以在启动时直接使用其中之一来更新您的策略:
var strat = new MyStrategy(new HttpContextAccessor());
请注意,在最初提出问题时,多租户与 ASP.NET 核心 IServiceProvider
系统交互的方式存在问题,也就是说,它没有。
从那时起,我们发布了 4.0.0-rc3-309
for the Autofac.Extensions.DependencyInjection
package 解决了这个问题。
变化是您需要将ConfigureServices
更新为return new AutofacServiceProvider(mtc);
,不再执行return mtc.Resolve<IServiceProvider>();
。