【问题标题】:Inject request scoped object at run time asp.net core在运行时注入请求范围的对象 asp.net core
【发布时间】:2019-04-23 08:32:00
【问题描述】:

我在 ASP.NET Core 管道中有一个中间件,我在其中像这样在运行时注入一个对象

public async Task Invoke(HttpContext context)
{
 _container.Inject(someObject);
 await _requestDelegate(context);
}

我现在面临的问题是,对于每个请求,它都会注入一个 this 的实例并且使我的容器膨胀。 如果我这样做_container.GetAllInstances<SomeType>(),我会得到 100 多个对象。有什么方法可以注入请求范围内的对象,并在请求完成后处理掉该对象?

【问题讨论】:

  • 似乎您正在将运行时数据与对象组合混合在一起,即not a great idea
  • 据我所知,您可以将范围生命周期与 AddScope 方法一起用于您的对象/每个请求。容器 IoC 将为您处理何时 Dispose 对象。如果您想检索使用相同接口类型注册的对象,则可以按名称注入它们。这就是原因。每个请求注入一个对象?以后会用吗?

标签: asp.net-core dependency-injection .net-core structuremap


【解决方案1】:

不应在运行时为每个请求配置依赖注入,而应在整个应用程序的应用程序启动时配置。

对于每个请求的实例,使用HttpContext.Items 管理请求数据是一种更好的方法。它是一个键值对存储,用于跨单个 HTTP 请求的共享对象。

在您的中间件中,您可以将对象添加到 HttpContext.Items 集合中: context.Items.Add("someObjectKey", someObject);

然后在控制器中(或任何你有 HttpContext 的地方),你可以得到对象:

if (context.Items.TryGetValue("someObjectKey", out object objSomeObject) 
    && objSomeObject is SomeObjectType someObject)) {
    // Do anything with your object here
}

如果你真的想使用 DI,你可以创建一个具有作用域生命周期的辅助类,它使用 IHttpContextAccessor 获取当前的 HttpContext,并以类型安全的方式提供你的对象。

public class SomeObjectAccessor
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public SomeObjectAccessor(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public SomeObject Object {
        get
        {
            if (_httpContextAccessor.HttpContext?.Items != null && _httpContextAccessor.HttpContext.Items.TryGetValue("someObjectKey", out object objSomeObject))
                return objSomeObject as SomeObject;
            return null;
        }
    }
}

或者,该类也可以充当工厂并在首次访问时基于 HttpContext 创建对象,那么您就不会使用HttpContext.Items。但这取决于这里的用例。

【讨论】:

  • 感谢以上,会试一试,但我也找到了另一种方法。上下文对象包含一个名为 RequestServices 的属性,它为我提供了服务提供者。使用服务提供者我也可以修改对象,像这样 var someObj = context.RequestServices.GetRequiredService() 我想知道这是否也是一个好方法
  • 另外我认为我们应该避免直接使用 HttpContext 因为模拟变得困难,我们应该使用某种包装器,就像你提到的那样。
  • 记得添加services.AddHttpContextAccessor();获取 IHttpContextAccessor 实例
【解决方案2】:

不清楚您要做什么。在运行时为每个请求注入一个对象的目的是什么?

您使用 ServicesCollection 在 ConfigureServices 方法中设置您的 DI,并使用内置的 AddScoped 方法注入对特定请求有效的对象。

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped(typeof(someclass), someObject);
}

如果您需要访问中间件中的 someObject 实例。只需将依赖项作为附加参数添加到 Invoke 方法中

public async Task Invoke(HttpContext context, IYourDependency someObject)
{
    await _requestDelegate(context);
}

希望对你有帮助

【讨论】:

  • 我从请求标头中读取了一些我想在运行时注入的值,应用程序不会知道该实例。它将根据头数据创建和注入
  • 您使用的是哪个 IoC 容器?不建议将容器注入控制器/类,但如果必须,实际上所有容器都支持作用域注入。他们使用的术语可能不同,例如InstancePerRequest (Autofac) 或 AddScoped (Asp.Net Core)。因此,根据您的逻辑,如果存在请求标头,请将实例注入容器。我仍然有点困惑,当它被注入容器后你会如何处理它?
猜你喜欢
  • 1970-01-01
  • 2011-06-12
  • 2019-02-12
  • 2015-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-26
相关资源
最近更新 更多