问题描述
的3.0将具有支持和的现在。为了尝试一下,我创建了以下配置一个ASP.NET Web API应用程序:
公共类全球:System.Web.HttpApplication { 保护无效的Application_Start(对象发件人,EventArgs的发送){ 无功配置= GlobalConfiguration.Configuration;
config.Routes.MapHttpRoute(默认,API / {}控制器);
RegisterDependencies(配置);
} 公共无效RegisterDependencies(HttpConfiguration配置){ VAR建设者=新ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); //创建每个租户记录器实例
builder.RegisterType&所述; LoggerService>()为< ILoggerService>()InstancePerTenant(); VAR MTC =新MultitenantContainer(
新RequestParameterTenantIdentificationStrategy(承租人),
builder.Build()); config.DependencyResolver =新AutofacWebApiDependencyResolver(MTC);
}
}
它能够完成任务,并创建一个 LoggerService
实例作为 ILoggerService
每个租户。我在这个阶段,我没能解决两个问题:
- 我用了提供的框中
RequestParameterTenantIdentificationStrategy
这里作为TenantIdentificationStrategy的只是这个演示应用程序。我能够通过实施ITenantIdentificationStrategy
界面创建我的自定义TenantIdentificationStrategy。然而,TryIdentifyTenant
的方法ITenantIdentificationStrategy
让你依靠静态实例,如的HttpContext。电流
这是一件好事,因为我希望我的API来举办不可知论者(我知道我可以委托这个工作交给托管层,但我想我不会在ASP.NET Web API环境要而不是)。有另一种方式的方式来实现这一点,我不会依赖一个静态实例? -
我也有机会登记为以下租户特定实例:
mtc.ConfigureTenant(tenant1,CB => cb.RegisterType<富>()
。至于<的IFoo>()InstancePerApiRequest());不过,我的情形之一,需要我通过构造函数的参数来传递房客的名字,我很想有类似如下:
mtc.ConfigureTenant((CB,tenantName)=> cb.RegisterType<富>()
。至于<的IFoo>()
.WithParameter(tenantNametenantName)
.InstancePerApiRequest());目前不存在这样的API。有另一种方式来做到这一点还是这种要求没有任何意义吗?
多租户支持上市已经有很长一段时间,它只是3.0是第一次,我们已经有一个包的NuGet它。 :)
的 RequestParameterTenantIdentificationStrategy
时,如记录,只是显示一种可能(和不建议)的方式很简单的例子,以确定承租人。你将不得不为自己选择如何根据操作上下文识别您的租户。这可能是从的web.config
价值,环境变量,或在当前环境下一些其他的事情。如果你不希望使用 HttpContext.Current
,不要。这是由你来挑,你得到这些信息。
(关于 RPTIStrategy
A注 - 未使用查询字符串或请求参数作为租户ID机制建议的一部分,我用的HttpContext ,它工作正常。这里只有这么多,你可以抽象出来,你必须真正触及裸机之前)。
有没有办法开箱提供你要求为注册的lambda语法,主要是因为承租人不通过解析过程通过。该决议过程是:
- 确定与战略承租人。
- 找到租户的配置一生范围。
- 使用标准Autofac解决风格的语法。
这是故意简单,类似于现有业务。在解决的时候,属于租户子寿命-范围的标签的与房客ID,但分辨率操作不知道租户ID ...所以在lambda不会工作(也可能不会很快,因为它会改变方式的根本性内部Autofac工作,如果它没有)。
要完成你要查找的内容,你可以在注册时使用
InstancePerTenant
扩展的组合...
VAR建设者=新ContainerBuilder();
builder.RegisterType&所述;富>()为<的IFoo>()InstancePerTenant();
...和注册
ITenantIdentificationStrategy
在你的容器的依赖关系。
builder.Register(myIdStrategy)。至于< ITenantIdentificationStrategy>();
然后,让你的类的
ITenantIdentificationStrategy
而非租户ID直接拿。使用策略来获取租户ID来代替。
如果你真的想获得幻想,你可以注册一个键控拉姆达能解决ID策略,然后获取租户ID。然后,你可以一个参数登记添加到像你这样的对象,但使用密钥的服务。 (我要去内存现在得走了,所以你必须在这里仔细检查我的语法,但它会是这样的...)
builder.Register(C =>
{VAR S = c.Resolve< ITenantIdentificationStrategy>();
对象ID;
s.TryIdentifyTenant(掉id);
返回ID;
})键控&所述;对象>(tenantId);builder.RegisterType<富>()
。至于<的IFoo>()
.WithParameter(
(PI,C)=> pi.Name ==tenantId
(PI,C)=> c.ResolveKeyed&所述;对象>(tenantId))
.InstancePerApiRequest();
同样,你会想仔细检查我这句话,但我pretty确认(或轻微的变化)应该工作得到你想要的东西。
Autofac 3.0 will have a MultitenantIntegration support and its preview release is out now. To try it out, I created an ASP.NET Web API application with the following configuration:
public class Global : System.Web.HttpApplication {
protected void Application_Start(object sender, EventArgs e) {
var config = GlobalConfiguration.Configuration;
config.Routes.MapHttpRoute("Default", "api/{controller}");
RegisterDependencies(config);
}
public void RegisterDependencies(HttpConfiguration config) {
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// creates a logger instance per tenant
builder.RegisterType<LoggerService>().As<ILoggerService>().InstancePerTenant();
var mtc = new MultitenantContainer(
new RequestParameterTenantIdentificationStrategy("tenant"),
builder.Build());
config.DependencyResolver = new AutofacWebApiDependencyResolver(mtc);
}
}
It gets the job done and creates a
LoggerService
instance as ILoggerService
per tenant. I have two problems at this stage which I wasn't able to solve:
I used out of the box provided
RequestParameterTenantIdentificationStrategy
here as the TenantIdentificationStrategy just for this demo application. I am able to create my custom TenantIdentificationStrategy by implementingITenantIdentificationStrategy
interface. However,TryIdentifyTenant
method of theITenantIdentificationStrategy
makes you rely on a static instance such asHttpContext.Current
which is something that I don't want in an ASP.NET Web API environment as I want my API to be hosting agnostic (I know that I can delegate this work to the hosting layer but I would rather not to). Is there another way to achieve this in a way that I won't rely on a static instance?I also have a chance to register tenant specific instance as below:
mtc.ConfigureTenant("tenant1", cb => cb.RegisterType<Foo>() .As<IFoo>().InstancePerApiRequest());
However, one of my situations requires me to pass the tenant name through the constructor parameter and I would love to have something like below:
mtc.ConfigureTenant((cb, tenantName) => cb.RegisterType<Foo>() .As<IFoo>() .WithParameter("tenantName", tenantName) .InstancePerApiRequest());
Currently there is no such an API. Is there another way to achieve this or this kind of requirement doesn't make any sense?
解决方案
Multitenant support has been available for a long time, it's just that 3.0 is the first time we've had a NuGet package for it. :)
The
RequestParameterTenantIdentificationStrategy
is, as documented, just a very simple example showing one possible (and not recommended) way to identify tenant. You will have to choose for yourself how to identify your tenant based on the operating context. It could be from a web.config
value, an environment variable, or some other thing in the current environment. If you don't want to use HttpContext.Current
, don't. It's up to you to pick where you get that info from.
(A note on the
RPTIStrategy
- the part that isn't recommended is using a querystring or request parameter as the tenant ID mechanism. I use HttpContext
in my production apps and it works fine. There's only so much you can abstract out before you have to actually touch the bare metal.)
There is no way out of the box to provide the lambda registration syntax you're asking for, primarily because tenant is not passed through the resolution process. The resolution process is:
Identify the tenant with the strategy.
Find the tenant's configured lifetime scope.
Use standard Autofac Resolve style syntax.
It's intentionally simple and analogous to the existing operations. At the time of resolve, the sub-lifetime-scope belonging to the tenant is tagged with the tenant ID but the resolution operation doesn't know about the tenant ID... so the lambda wouldn't work (and probably won't anytime soon because it'd change the fundamental internals of the way Autofac works if it did).
To accomplish what you're looking for, you can use a combination of the
InstancePerTenant
extension when registering...
var builder = new ContainerBuilder();
builder.RegisterType<Foo>().As<IFoo>().InstancePerTenant();
...and registering the
ITenantIdentificationStrategy
as a dependency in your container.
builder.Register(myIdStrategy).As<ITenantIdentificationStrategy>();
Then make your class take an
ITenantIdentificationStrategy
rather than the tenant ID directly. Use the strategy to get the tenant ID instead.
If you REALLY want to get fancy, you could register a keyed lambda that resolves the ID strategy, then gets the tenant ID. Then you could add a parameter registration to the object like you did but using a keyed service. (I'm going to go by memory now, so you'll have to double-check my syntax here, but it'll be something like this...)
builder.Register(c =>
{ var s = c.Resolve<ITenantIdentificationStrategy>();
object id;
s.TryIdentifyTenant(out id);
return id;
}).Keyed<object>("tenantId");
builder.RegisterType<Foo>()
.As<IFoo>()
.WithParameter(
(pi, c) => pi.Name == "tenantId",
(pi, c) => c.ResolveKeyed<object>("tenantId"))
.InstancePerApiRequest();
Again, you'll want to double-check me on that, but I'm pretty sure that (or a minor variation) should work to get you what you want.
这篇关于Autofac多租户IoC容器在ASP.NET Web API应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!