Ninject中的.NET Core DI作用域生命周期

4

编辑:由于许多用户错误地将此视为ASP.NET特定问题。请注意,我的应用程序不是Web应用程序,我没有使用ASP.NET应用程序(我正在使用其功能,该功能在.NET Core中也可用)。


最近,当我在配置一个Entity Framework DbContext的生命周期时,在Ninject DI中,我一直在研究.NET Core依赖注入,因为它已经有了注册DbContext的功能,并且可以在这里找到。默认上下文生命周期是ServiceLifetime.Scoped
在代码片段中,我们可以读到在ASP.NET应用程序中,“scoped”意味着:

为每个服务器请求创建范围

namespace Microsoft.Extensions.DependencyInjection
{
    //
    // Summary:
    //     Specifies the lifetime of a service in an Microsoft.Extensions.DependencyInjection.IServiceCollection.
    public enum ServiceLifetime
    {
        //
        // Summary:
        //     Specifies that a single instance of the service will be created.
        Singleton = 0,
        //
        // Summary:
        //     Specifies that a new instance of the service will be created for each scope.
        //
        // Remarks:
        //     In ASP.NET Core applications a scope is created around each server request.
        Scoped = 1,
        //
        // Summary:
        //     Specifies that a new instance of the service will be created every time it is
        //     requested.
        Transient = 2
    }
}

我正在尝试在Ninject DI中实现类似的功能,但很难说明在.NET Core应用程序(不是Web应用程序!)中等效的作用域生命周期。

Ninject具有InRequestScope方法,但仅适用于Web应用程序,因此与.NET Core DI ServiceLifetime.Scoped设置非常不同。

也许我需要在Ninject中创建某种自定义范围,但是-我无法确切说明如何实现与.NET Core DI中相同的作用域行为。为此,我需要了解.NET Core应用程序在.NET Core DI上下文中的作用域生命周期是如何工作的。 我猜测,创建了一个DbContext实例,并在应用程序退出时被处理。

因此我的问题是

  • .NET Core DI的scope生命周期设置是如何工作的,它的生命周期是什么?
  • Ninject DI是否可以实现类似的行为?

1
@tura08 请再仔细阅读我的问题。 - Categle
这个代码库包含了一个示例,展示了如何使用作用域将 Ninject 集成到 ASP.NET Core 中。点击此处查看示例。 - Steven
@Steven,抱歉。我明确说过至少两次,这不是关于Web应用程序的问题,而是关于将Ninject的InRequestScope移植到.NET Core应用程序中,就像.NET Core DI正在做的那样。我已经编辑了问题,现在更清楚了 :) - Categle
嗨Rusco,那个代码库仍然给你一些关于如何做这个的线索。 - Steven
有趣的一个。 - Lucas
2个回答

3

.NET Core DI作用域生命周期设置是如何工作的,它的生命周期是什么?

.Net Core内部使用名为ServiceScope的类。当调用新请求(例如Web请求)时,将创建新实例,并包含新的服务提供程序。在请求期间,此服务提供程序用于依赖项解析。完成请求后,范围被处理并且其服务提供程序及其已解析的服务也被处理。

  internal class ServiceScope : IServiceScope, IDisposable
  {
    private readonly Microsoft.Extensions.DependencyInjection.ServiceProvider _scopedProvider;

    public ServiceScope(Microsoft.Extensions.DependencyInjection.ServiceProvider scopedProvider)
    {
      this._scopedProvider = scopedProvider;
    }

    public IServiceProvider ServiceProvider
    {
      get
      {
        return (IServiceProvider) this._scopedProvider;
      }
    }

    public void Dispose()
    {
      this._scopedProvider.Dispose();
    }
  }

在Ninject DI中是否可能实现类似的行为?

正如您已经注意到的,实现自定义范围是正确的方法。您可以查看另一个答案中如何实现:

Ninject - 当RequestScope无意义时,在哪个作用域下绑定DbContext?

编辑:

.NET Core DI的原则与任何其他IOC容器相同。它通过DI向您的对象(MVC控制器等)提供依赖项,并控制其生命周期。

  • 如果您为 DbContext 指定了 singleton 生命周期,则只会创建一个,当请求时由 DI 提供并在整个应用程序/容器生命周期中保留在内存中。
  • 如果您指定了瞬态,则每次请求 DbContext 时都会得到一个新的。
  • 如果您指定了作用域,则 DbContext 的生命周期绑定到某个可处理范围,该范围在某个逻辑请求的开始时创建(在 asp 的情况下是 http 请求)。当 DI 第一次请求 DbContext 时,会创建一个新的 DbContext 并将其保存在内存中,在随后的 DI 请求期间始终获得相同的 DbContext,直到范围被处理(在 asp 的情况下是 http 请求结束)以及其中的 DbContext。

您可以找到与 TransactionScope 相似的类比。在同一 TransactionScope 中的所有 sqlCommands 都被列入同一 sql 事务中,直到范围被处理/提交。


@Rusco。你不使用using的原因是因为asp.net core会自动处理! - Jan Muncinsky
@Rusco 这意味着你要么让框架创建和处理作用域,要么你必须自己控制作用域的生命周期(如果你不是在开发 ASP 应用的话)。无论如何,都会有这样一段代码。Ninject 示例也是完全相同的。 - Jan Muncinsky
我看到了...但我想知道它是如何实现的?我的意思是,.NET Core DI如何能够在每个dbcontext调用时不强制我们创建一个新的上下文?那背后的魔法是如何运作的,他们是怎样做到的呢?我们能否在.NET Core应用程序中使用Ninject实现类似的功能?比如在应用程序的更广泛上下文中使用“using”? - Categle
哦,抱歉。在.NET Core DI中,我可以这样做(上下文将自动注入构造函数):https://pastebin.com/raw/8tCBq59F。在Ninjext中,我也可以使用相同的方式(构造函数注入)。然而,看了你在另一个问题中的回答后,我必须使用“using”范围:https://pastebin.com/raw/uKLFP4sj。而这正是我想避免的,我希望拥有成员设置实例来维持我的应用程序的生命周期。希望你现在明白了,对不便表示歉意。 - Categle
@Rusco,如果您需要应用程序生命周期的实例,则单例模式适用。如果您可以找到某些逻辑调用的边界,例如mvc控制器http调用、消息队列消费者调用甚至桌面应用程序中的单击事件处理程序,则作用域生命周期适用。对于所有这些情况都适用相同的方法,您将创建范围(使用using)(或由mvc框架完成),并在此范围内从容器中解析对象图的根,例如mvc控制器(可以直接或间接依赖于dbcontext),并在其上调用请求的方法。 - Jan Muncinsky
显示剩余5条评论

-2

感谢你的回答,Anupam Singh。请再次阅读我的问题。这不是关于ASP.NET,也不是Web应用程序。你没有回答我的问题。我明确地说了至少两次,这不是针对Web应用程序的,而是关于将Ninject的InRequestScope移植到.NET Core应用程序中,就像.NET Core DI正在做的那样。 - Categle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接