Short answer:
check this project. However, it relies on Ninject 4.0.0 which is still in beta version and it seems far from a final version (source). For Ninject 3.3.x look below.
Long answer:
Thanks to @Steven
I managed to create a working solution of ASP.NET Core 2.0 and Ninject (both 3.3.x and 4.0). The code is mainly from Missing-Core-DI-Extensions Git repo, so great thanks to dotnetjunkie.
The following must be performed regardless of referenced Ninject version:
1) Include AspNetCoreExtensions.cs and AspNetCoreMvcExtensions.cs in your project.
2) Create a very simple service to use for testing the DI: TestService
that implements ITestService
:
public class TestService : ITestService
{
public int Data { get; private set; }
public TestService()
{
Data = 42;
}
}
public interface ITestService
{
int Data { get; }
}
Change Startup.cs
as indicated below:
1) add these members
private readonly AsyncLocal<Scope> scopeProvider = new AsyncLocal<Scope>();
private IKernel Kernel { get; set; }
private object Resolve(Type type) => Kernel.Get(type);
private object RequestScope(IContext context) => scopeProvider.Value;
2) Add to ConfigureServices(IServiceCollection services)
(at the end)
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddRequestScopingMiddleware(() => scopeProvider.Value = new Scope());
services.AddCustomControllerActivation(Resolve);
services.AddCustomViewComponentActivation(Resolve);
3) Add to Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
(at the beginning)
Kernel = RegisterApplicationComponents(app, loggerFactory);
4) Add the following method and inner class:
private IKernel RegisterApplicationComponents(
IApplicationBuilder app, ILoggerFactory loggerFactory)
{
// IKernelConfiguration config = new KernelConfiguration();
Kernel = new StandardKernel();
// Register application services
foreach (var ctrlType in app.GetControllerTypes())
{
Kernel.Bind(ctrlType).ToSelf().InScope(RequestScope);
}
Kernel.Bind<ITestService>().To<TestService>().InScope(RequestScope);
// Cross-wire required framework services
Kernel.BindToMethod(app.GetRequestService<IViewBufferScope>);
Kernel.Bind<ILoggerFactory>().ToConstant(loggerFactory);
return Kernel;
}
private sealed class Scope : DisposableObject { }
5) Create BindToMethod
extension method
public static class BindingHelpers
{
public static void BindToMethod<T>(this IKernel config, Func<T> method) =>
config.Bind<T>().ToMethod(c => method());
}
6) Test DI by injecting custom service into a controller, setting a breakpoint into test service constructor and checking the call stack. Besides providing an instance, the call stack should hit custom code to integrate Ninject (e.g. ConfigureRequestScoping
method)
IKernel
has been deprecated in version 4, so IReadOnlyKernel and IKernelConfiguration classes should be used (although above code should work).
1) Use the new class (IReadOnlyKernel
)
private readonly AsyncLocal<Scope> scopeProvider = new AsyncLocal<Scope>();
private IReadOnlyKernel Kernel { get; set; }
private object Resolve(Type type) => Kernel.Get(type);
private object RequestScope(IContext context) => scopeProvider.Value;
2) 3) are the same
4) The method is slightly different:
private IReadOnlyKernel RegisterApplicationComponents(
IApplicationBuilder app, ILoggerFactory loggerFactory)
{
IKernelConfiguration config = new KernelConfiguration();
// Register application services
foreach (var ctrlType in app.GetControllerTypes())
{
config.Bind(ctrlType).ToSelf().InScope(RequestScope);
}
config.Bind<ITestService>().To<TestService>().InScope(RequestScope);
// Cross-wire required framework services
config.BindToMethod(app.GetRequestService<IViewBufferScope>);
config.Bind<ILoggerFactory>().ToConstant(loggerFactory);
return config.BuildReadonlyKernel();
}
5) The extension must use an IKernelConfiguration
public static class BindingHelpers
{
public static void BindToMethod<T>(
this IKernelConfiguration config, Func<T> method) =>
config.Bind<T>().ToMethod(c => method());
}
Scope
andIReadOnlyKernel
. Last commit was done about 1 year ago, so it might not be compatible with the current stable version of Ninject (3.3.0) and/or ASP.NET Core (2.0). – BegatConfigureRequestScoping
), so it works. Should I provide an answer containing working examples for both versions? It is a little bit different for version 3.3.1 like you said and also a minor change is required to fix an issue for 4.0. – Begat