4

Edit: Due to lots of users mistakenly taking this as a ASP.NET specific question. Please note that my application is not a web application and I'm not using ASP.NET application (I'm using it's funtionality, that is available in .NET Core as well).


Recently, while configuring an Entity Framework DbContext lifetime in a Ninject DI, I have been digging through the .NET Core Dependency Injection, because it already has a functionality for registering DbContext and can be found here. The default context life time is ServiceLifetime.Scoped.

In the code peek, we can read that in the ASP.NET applications, "scoped" means:

scope is created around each server request

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
    }
}

I'm trying to achieve a similar functionality in Ninject DI but it's really hard to state what would be the equivalent of scoped life time in Ninject, while speaking about .NET Core application (that isn't a web application!).

Ninject has that InRequestScope method, however it's only available for web applications, so it's really different from the .NET Core DI ServiceLifetime.Scoped setting.

Perhaps I would have to create some sort of a custom scope in Ninject, but still - I'm not really able to state, how to achieve exact the same scoped behaviour as in the .NET Core DI. To do that I need to be aware of how is the scoped life time working in context of a .NET Core application in .NET Core DI. My guess would be that there's one instance of a DbContext being created and is being disposed once the application quits.

Hence my questions:

  • How is .NET Core DI scope life time setting working and what is it's life cycle?
  • Is it possible to achieve a similar behaviour in Ninject DI?
Categle
  • 514
  • 1
  • 8
  • 22
  • Possible duplicate of [What is the difference between services.AddTransient, service.AddScope and service.AddSingleton methods in Asp.Net Core?](https://stackoverflow.com/questions/38138100/what-is-the-difference-between-services-addtransient-service-addscope-and-servi) – marcusturewicz Jul 04 '18 at 01:49
  • 1
    @tura08 Please read my question again. – Categle Jul 04 '18 at 02:56
  • [This repository](https://github.com/dotnetjunkie/Missing-Core-DI-Extensions/blob/master/src/SampleApplication.Ninject/Startup.cs) contains an example of how to integrate Ninject in ASP.NET Core using scoping. – Steven Jul 04 '18 at 08:23
  • @Steven I'm sorry. I clearly said, at least twice that this is not for the web application and this is about porting a `InRequestScope` of Ninject for .NET Core application just like .NET Core DI is doing it. I have edited the question so it will be more clear now :) – Categle Jul 04 '18 at 10:33
  • Hi Rusco, that repository still gives you some clues on how to do this. – Steven Jul 04 '18 at 11:04
  • Interesting one. – Lucas Jul 05 '18 at 23:26

2 Answers2

3

How is .NET Core DI scope life time setting working and what is it's life cycle?

.Net core internally works with class called ServiceScope. When new request is called (e.g. web request) new instance is created, with new service provider included. During request this service provider is used for dependency resolution. After request is finished, scope is disposed and also its service provider with its resolved services.

  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();
    }
  }

Is it possible to achieve a similar behaviour in Ninject DI?

As you have already noticed implementing custom scope is way to go. You can check how to do this in another answer:

Ninject - In what scope DbContext should get binded when RequestScope is meaningless?

EDIT:

Principle of .NET Core DI is the same like any other IOC container. It provides dependencies to your objects (MVC controllers etc.) by DI and controls its lifetime.

  • If you specify singleton lifetime for your DbContext than only one is created, provided by DI when requested and hold in memory for whole application/container lifetime.
  • If you specify transient you get new one all the time DbContext is requested.
  • If you specify scoped, lifetime of DbContext is bound to some disposable scope, which is created on the beggining of some logical request (http request in case of asp). When DbContext is requested by DI for the first time, new one is created, hold in memory and you get always the same during subsequent DI requests until the scope is disposed (with end of http request in case of asp) and DbContext with it.

You can find similar parallel with TransactionScope. Here all the sqlCommands within the same TransactionScope are enlisted into the same sql transaction util the scope is disposed/committed.

Jan Muncinsky
  • 4,282
  • 4
  • 22
  • 40
  • The solution given in other answer is still different implementation. I could create DbContext with `using` without Ninject. The main difference between .NET Core DI is that you don't have to use `using` statement to deliver a valid instance of DbContext. You simply register it as a provider and somehow it works. – Categle Jul 08 '18 at 20:58
  • @Rusco. Reason why you don't use using is because asp.net core it does it for you! – Jan Muncinsky Jul 08 '18 at 21:23
  • @Rusco So it means either you let the creating and disposal of scope on framework, or you must control the lifetime of scope by yourself (as you are not developing asp app). Anyway there will be always such a piece of code. Ninject example is exactly the same. – Jan Muncinsky Jul 08 '18 at 21:37
  • I see... But I wonder how is it done? I mean, how .NET Core DI is able to not force us to create a new context on every dbcontext call? How is that behind-the-scenes magic working, how do they do that? And could we achieve something similar in the .NET Core app using Ninject? Like using the `using` in a wider context of our app? – Categle Jul 08 '18 at 23:09
  • @Rusco, I tried to extend my answer, but I'm not sure whether we're on the same wave. Maybe would be helpful to show what exactly you want achieve. – Jan Muncinsky Jul 09 '18 at 10:39
  • Oh, sorry. In the .NET Core DI I'm able to do this (context will be automatically injected in the constructor): https://pastebin.com/raw/8tCBq59F . In Ninjext I can do the same (constructor injection). However, looking at your answer in the other question, I would have to use the `using` scope: https://pastebin.com/raw/uKLFP4sj And this is what I want to avoid, I would like to have member-set instance for the life time of my application. Hope you understand now and sorry for the inconvenience. – Categle Jul 09 '18 at 16:13
  • @Rusco, if you need the instance for the application lifetime then that's where the singleton fits in. Scoped lifetime fits in if you can find boundaries of some logical call like mvc controller http call, message queue consumer call or even click event handler in desktop app. For all of them applies the same, you will create the scope (with `using`) (or it's done by mvc framework) and inside this scope the root of your object graph like mvc controller (that can directly or indirectly depend on dbcontext) is resolved from the container and requsted method is called on it. – Jan Muncinsky Jul 09 '18 at 17:26
  • If you are really ok with having just one instance during application lifetime, than in Ninject you can bind it in singletone scope and on the application shutdown call `kernel.Dispose()`, which will also dispose your singletones. – Jan Muncinsky Jul 09 '18 at 17:44
  • Nice answer, bounty awarded. – Lucas Jul 09 '18 at 23:44
  • @JanMuncinsky Thank you for your effort and details. Now I understand more. – Categle Jul 11 '18 at 00:22
-2

There is extension method called InRequestScope, which is available in Ninject.Web.Common nuget package.

InRequestScope : https://github.com/ninject/Ninject.Web.Common/wiki/InRequestScope

You can correlate .net core and ninject DI methods from https://github.com/ninject/Ninject/wiki/Object-Scopes

Anupam Singh
  • 1,158
  • 13
  • 25
  • Thank you for your answer Anupam Singh. Please read my question once again. It's NOT about the ASP.NET, this is not web application. You didn't answer my questions. I clearly said, at least twice that this is not for the web application and this is about porting a `InRequestScope` of Ninject for .NET Core application just like .NET Core DI is doing it. – Categle Jul 04 '18 at 10:29