的方案: 的
我需要为相同的 Web应用程序(appdomain)中的相同的接口定义提供不同的接口实现,但是要提供给不同的 “范围”
想象一下这样一个简单的分层Web内容结构(如果您不熟悉SharePoint):
RootWeb (SPSite) (ctx here)
|______SubWeb1 (SPWeb) (ctx here)
|______SubWeb2 (SPWeb)
|______SubWeb3 (SPWeb)
|_______SubWeb3.1 (SPWeb) (ctx here)
|_______SubWeb3.2 (SPWeb)
RootWeb,SubWeb1和SubWeb3.1提供上下文。那就是我实现了一个特定于某个层次结构级别的AppIsolatedContext类。如果某个级别未提供上下文,则它将从父节点继承上下文,依此类推。例如,SubWeb3将从RootWeb继承其上下文。然而,SubWeb3.1提供了自己的孤立上下文。
孤立的上下文只是一个静态的ConcurrentDictionary。
好的,到目前为止一切顺利。现在关于Autofac(我是Autofac和任何其他DI容器的新手 - 虽然不是IoC的原理)......我不确定我是如何正确设置它来正确处理对象的。实际上它不应该是一个问题,因为对象(一旦它们被创建)应该存在直到appdomain被回收(将它们视为“每个孤立的上下文单例”)。
我倾向于做那样的事情:
// For completeness.. a dummy page which creates a "dummy" context
public partial class _Default : Page
{
private static AppIsolatedContext _dummyContainer = new AppIsolatedContext();
public _Default()
{
_dummyContainer.ExceptionHandler.Execute("Test Message");
}
}
// The isolated context which holds all the "context" specific objects
public class AppIsolatedContext
{
public static IContainer Container { get; set; }
public IExceptionHandler ExceptionHandler { get; set; }
//public ISomething Something { get; set; }
//public ISomethingElse SomethingElse { get; set; }
public AppIsolatedContext()
{
// set up autofac
// Create your builder.
ContainerBuilder builder = new ContainerBuilder();
// Usually you're only interested in exposing the type
// via its interface:
builder.RegisterType<MailNotificationHandler>().As<INotificationHandler>();
builder.RegisterType<ExceptionHandler>().As<IExceptionHandler>();
Container = builder.Build();
using (ILifetimeScope scope = Container.BeginLifetimeScope())
{
ExceptionHandler = scope.Resolve<IExceptionHandler>();
//Something = scope.Resolve<ISomething>();
//SomethingElse = scope.Resolve<ISomethingElse>();
}
}
}
当然,我的应用程序不仅限于这些“上下文单例”实例。我也会请求生命周期实例..但这就是ASP.NET集成模块的用途吗?我希望它们也可以无缝集成到SharePoint(2013)中:)
所以我的问题是 我提出的建议是否可以,或者我需要弄脏手?如果是这样,某些方向将是现象 ......
通过Autofac的文档挖掘我偶然发现了它的多租户功能。 我相信这也可能适合我的目的..任何人都可以证实这一点吗?
using System;
using System.Web;
using Autofac.Extras.Multitenant;
namespace DemoNamespace
{
public class RequestParameterStrategy : ITenantIdentificationStrategy
{
public bool TryIdentifyTenant(out object tenantId)
{
tenantId = AppIsolatedContext.Current.Id; // not implemented in the dummy class above, but present in the real thing.
return !string.IsNullOrWhiteSpace(tenantId);
}
}
}
如果有什么不是水晶 - 请不要犹豫告诉我:)
答案 0 :(得分:5)
免责声明:这是一个相当重要的问题,考虑到这一点以及我对SharePoint 2013的熟悉程度,我会尽力回答,但你需要在某种程度上适应你的答案需求。
我将使用命名的生命周期范围来构建它。使用命名范围的层次结构,而不是使用自己的容器进行上下文。这就是多租户支持的工作方式;它也是ASP.NET每网络请求支持的工作方式。
首先,您需要阅读the Autofac wiki page on instance scopes以及this primer on Autofac lifetimes。这些都不是小文章,但都有重要的概念需要理解。我在这里解释的一些内容只有在了解了生命范围时才有意义。
生命周期范围是可嵌套的,这是您共享单身人士或每个网络请求实例的方式。在应用程序的根目录是一个包含所有注册的容器,并从中生成范围。
在更多与代码相关的格式中,它是这样的:
var builder = new ContainerBuilder();
var container = builder.Build();
using(var child = container.BeginLifetimeScope())
{
using(var childOfChild = child.BeginLifetimeScope())
{
}
}
您实际上是在范围之外解析组件 - 容器本身就是范围。
关于生命范围的关键事项:
BeginLifetimeScope
时动态注册。这就是多租户对Autofac的支持。每个租户都有自己的命名生命周期范围。
不幸的是,多租户支持是一个级别:应用程序容器生成特定于租户的“根”范围,但就是这样。您拥有这些上下文的站点层次结构具有多个级别,因此多租户支持不起作用。但是,您可以查看源代码以获取创意。
我要做的是在每个级别命名范围。每个站点都会通过一个ILifetimeScope
来解决问题。在代码中,它看起来有点像:
var builder = new ContainerBuilder();
// RootWeb will use the container directly and build its per-web-request
// scope from it.
var container = builder.Build();
// Each sub web will get its own scope...
using(var sw1Scope = container.BeginLifetimeScope("SubWeb"))
{
// Each child of the sub web will get a scope...
using(var sw11Scope = sw1Scope.BeginLifetimeScope("SubWeb"))
{
}
using(var sw12Scope = sw1Scope.BeginLifetimeScope("SubWeb"))
{
}
}
注意我将每个级别的子Web范围标记为“SubWeb” - 这将允许您在容器级别和子Web级别注册中具有“每子网站实例”类型的注册。
// Register a "singleton" per sub-web:
builder.RegisterType<Foo>()
.As<IFoo>()
.InstancePerMatchingLifetimeScope("SubWeb");
现在,显然,这是一个概念性的东西 - 你实际上无法将所有内容包装在那样的语句中。您需要以不同方式管理您的创建和处置,因为创建将发生在与处置不同的地方。
您可以查看ASP.NET和多租户来源,以获取有关如何执行此操作的建议。一般算法将是:
BeginLifetimeScope
现在,您可以通过将子Web ID的根级别字典保留到范围来进行另一步,这样您根本不需要每个级别的“上下文”对象。它更像是DependencyResolver.Current.GetService<T>
种模式。如果您查看Autofac多租户支持中的MultitenantContainer
如何工作,您将看到类似的租户ID到范围字典。
事实上,多租户支持将是一个很好的模式,特别是如果您还希望拥有每个Web请求范围。 Autofac ASP.NET支持要求您传入父ILifetimeScope
,从中生成子Web请求生存期范围。多租户支持在那里添加了一些动态方面,所以当ASP.NET支持调用BeginLifetimeScope
时,多租户部分会自动计算(通过租户标识)哪个租户应该是当前请求的父级。您可以使用子网的层次结构执行相同的操作。但是,再次,多租户支持是一个扁平结构,而您的子网是层次结构,因此多租户支持不会只是工作 。
这里有很长的路要说你有一个有趣的用例,但是你的手会很脏。