gpt4 book ai didi

c# - 覆盖范围内依赖项的正确方法

转载 作者:太空宇宙 更新时间:2023-11-03 22:59:05 26 4
gpt4 key购买 nike

我正在使用简单注入(inject)器。我有一个从一开始就使用 DI 的后台处理器。它将选择要运行的作业,然后运行它们。但是,每个作业都需要在其自己的范围内运行,以便我可以覆盖一些上下文相关性。例如,作业需要在特定的安全上下文(创建作业的上下文)中运行,因此我需要启动一个新范围并覆盖 ISecurityContext 注入(inject),以便作业得到适当保护.

为此,我创建了一个新容器(使用正确的 ISecurityContext)并启动一个范围,然后运行该作业,但我不确定这样做是否合适.

运行作业

private readonly Func<ISecurityContext, Container> _containerFactory;

internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;

using (var container = _containerFactory(securityContext))
using (AsyncScopedLifestyle.BeginScope(container)) {
// Run the job within this scope.
}
}

DI 位

container.RegisterSingleton<Func<ISecurityContext, Container>>(() => securityContext => {
var c = new Container();

RegisterDependencies(c);

c.Options.AllowOverridingRegistrations = true;
c.Register<ISecurityContext>(() => securityContext, Lifestyle.Scoped);

return c;
});

我觉得不对,但我不确定正确的解决方案是什么。

最佳答案

简单注入(inject)器文档 warns关于您正在做的事情,请说明:

Warning: Do not create an infinite number of Container instances (such as one instance per request). Doing so will drain the performance of your application. The library is optimized for using a very limited number of Container instances. Creating and initializing Container instances has a large overhead, but resolving from the Container is extremely fast once initialized.

一般来说,您应该只为每个应用程序创建一个 Container 实例。这不仅从性能的角度来看是成立的,而且这种“子容器”的创建通常充满了怪癖和缺陷。例如,如何确保注册在整个应用程序中是单例的?

因此,不要滥用容器作为运行时状态,而是将其存储在别处。您可以使用 Scope 实例作为作用域状态的字典,但是为注册为 Scoped 实例的 ISecurityContext 创建一个简单的包装器同样容易并在创建范围后直接初始化,如以下示例所示。

// Can be part of your Composition Root
internal sealed class SecurityContextWrapper : ISecurityContext
{
// One of the rare cases that Property Injection makes sense.
public ISecurityContext WrappedSecurityContext { get; set; }

// Implement ISecurityContext methods here that delegate to WrappedSecurityContext.
}


// Composition Root. Only have 1 container for the complete application
c = new Container();

RegisterDependencies(c);

c.Register<SecurityContextWrapper>(Lifestyle.Scoped);
c.Register<ISecurityContext, SecurityContextWrapper>(Lifestyle.Scoped);


// Job logic
private readonly Container _container;

internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;

using (AsyncScopedLifestyle.BeginScope(_container)) {
// Resolve the wapper inside the scope
var wrapper = _container.GetInstance<SecurityContextWrapper>();
// Set it's wrapped value.
wrapper.WrappedSecurityContext = securityContext;

// Run the job within this scope.
}
}

或者,如果您使用 Scope 作为状态,您可以注入(inject)一个 Scope 实例作为 SecurityContextWrapper 的构造函数参数。这消除了使用属性注入(inject)的需要,但确实使您的 SecurityContextWrapper 依赖于简单注入(inject)器:

// Can be part of your Composition Root
internal sealed class SecurityContextWrapper : ISecurityContext
{
ISecurityContext _wrappedSecurityContext;

public SecurityContextWrapper(Scope scope)
{
_wrappedSecurityContext= (ISecurityContext)scope.GetItem(typeof(ISecurityContext));
}

// Implement ISecurityContext methods here that delegate to WrappedSecurityContext.
}

// Composition Root. Only have 1 container for the complete application
c = new Container();

RegisterDependencies(c);

c.Register<ISecurityContext, SecurityContextWrapper>(Lifestyle.Scoped);


// Job logic
private readonly Container _container;

internal async Task RunJob(BackgroundJob job) {
var parameters = job.GetParameters();
var securityContext = parameters.SecurityContext;

using (var scope = AsyncScopedLifestyle.BeginScope(_container)) {
// Set it's wrapped value.
scope.SetItem(typeof(ISecurityContext), securityContext);

// Run the job within this scope.
}
}

关于c# - 覆盖范围内依赖项的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44015829/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com