lap*_*sus 2 c# inversion-of-control autofac object-lifetime
场景:
我需要为同一 Web应用程序(appdomain)中的相同接口定义提供不同的接口实现,但要提供不同的“作用域”。
想象这样一个简单的分层Web内容结构(如果您不熟悉SharePoint):
RootWeb (SPSite) (ctx here)
|______SubWeb1 (SPWeb) (ctx here)
|______SubWeb2 (SPWeb)
|______SubWeb3 (SPWeb)
|_______SubWeb3.1 (SPWeb) (ctx here)
|_______SubWeb3.2 (SPWeb)
Run Code Online (Sandbox Code Playgroud)
RootWeb,SubWeb1和SubWeb3.1提供上下文。也就是说,我实现了一个AppIsolatedContext类,该类特定于某个层次结构级别。如果级别不提供上下文,则它从父节点继承上下文,依此类推。例如,SubWeb3将从RootWeb继承其上下文。但是,SubWeb3.1提供了自己的隔离上下文。
隔离的上下文只是静态的ConcurrentDictionary。
好的,到目前为止很好。现在关于Autofac(我是Autofac和任何其他DI容器的新手,尽管不了解IoC原理)...我不确定如何正确设置它以正确处理对象。实际上,这不应该是什么大问题,因为对象(一旦创建)就应该一直存在,直到appdomain被回收(将它们视为“每个隔离上下文单例”)为止。
我倾向于做这样的事情:
RootWeb (SPSite) (ctx here)
|______SubWeb1 (SPWeb) (ctx here)
|______SubWeb2 (SPWeb)
|______SubWeb3 (SPWeb)
|_______SubWeb3.1 (SPWeb) (ctx here)
|_______SubWeb3.2 (SPWeb)
Run Code Online (Sandbox Code Playgroud)
当然,我的应用程序不限于这些“上下文单例”实例。我也将按请求提供生命周期实例..但这就是ASP.NET集成模块对的吗?我希望它们也可以无缝集成到SharePoint(2013)中:)
所以我的问题是我提出的建议还好吗?还是需要弄脏我的手?如果是这样,那么某个方向将是惊人的 ...
浏览Autofac的文档时,我偶然发现了其多租户功能。我相信这也可能适合我的目的。.有人可以确认吗?
// 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>();
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果有任何东西不是水晶-请不要犹豫告诉我:)
免责声明:这是一个相当重要的问题,并且鉴于这个问题以及我对SharePoint 2013的某种程度的不熟悉,我会尽力回答,但您需要在某种程度上适应您的需求。
我将使用命名生命周期作用域来构造它。与其使用自己的容器的上下文,不如使用命名作用域的层次结构。这就是多租户支持的工作方式;这也是ASP.NET每个Web请求支持的工作方式。
您首先要阅读有关实例范围的Autofac Wiki页面以及有关Autofac生存期的入门。这些都不是小文章,但是都有重要的概念需要理解。如果您了解生命周期范围,那么我在这里解释的一些内容才有意义。
生命周期作用域是可嵌套的,这就是您共享单例或按Web实例请求的方式的方式。在应用程序的根部是一个包含所有注册内容的容器,您可以从中生成作用域。
在与代码更多相关的格式中,它是这样的:
var builder = new ContainerBuilder();
var container = builder.Build();
using(var child = container.BeginLifetimeScope())
{
using(var childOfChild = child.BeginLifetimeScope())
{
}
}
Run Code Online (Sandbox Code Playgroud)
您实际上是在范围之外解析组件-容器本身就是一个范围。
有关生命周期范围的关键事项:
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"))
{
}
}
Run Code Online (Sandbox Code Playgroud)
注意,我将子网站范围的每个级别标记为“ SubWeb”-这将使您在容器级别和子网站级别的注册中都具有“每个子网站实例”类型的注册。
// Register a "singleton" per sub-web:
builder.RegisterType<Foo>()
.As<IFoo>()
.InstancePerMatchingLifetimeScope("SubWeb");
Run Code Online (Sandbox Code Playgroud)
现在,显然,这是一个概念性的东西-您实际上无法使用这样的语句包装所有内容。您需要对创建和处置进行不同的管理,因为创建将在与处置不同的地方进行。
您可以查看ASP.NET和多租户源代码,以获得有关如何执行此操作的想法。通用算法为:
BeginLifetimeScope现在,您可以采取另一步骤,将子Web ID的根级别词典保留在范围内,从而根本不需要每个级别的“上下文”对象。它更像是DependencyResolver.Current.GetService<T>一种模式。如果您查看MultitenantContainerAutofac多租户支持中的工作方式,您会看到类似的租户ID范围字典。
实际上,多租户支持将是一个很好的模式,特别是如果您还希望具有每个Web请求范围的话。Autofac ASP.NET支持要求您传入一个父项,ILifetimeScope将从其派生子级Web请求生存期范围。多租户支持在那里增加了一些动态方面,因此当ASP.NET支持调用BeginLifetimeScope事物的多租户部分时(通过租户标识)会自动找出哪个租户应该是当前请求的父级。您可以对子站点的层次结构执行相同的操作。但是,同样,多租户支持是一个平面结构,而您的子站点是一个层次结构,因此多租户支持将不仅仅适用。
这很长一段话可以说您在这里有一个有趣的用例,但是您会变得很脏。
| 归档时间: |
|
| 查看次数: |
1750 次 |
| 最近记录: |