如何将Ninject集成到ASP.NET Core 2.0 Web应用程序中?

问题描述 投票:10回答:1

我发现Ninject最近有introduced support for .NET Standard 2.0 / .NET Core 2.0

但是,我找不到实际将其集成到Web应用程序中的任何扩展(例如类似于Ninject.Web.Common

从旧的ASP.NET MVC解决方案的代码看,我意识到整个机制是不同的,因为经典的机制依赖于ASP.NET核心中不再提供的WebActivatorEx.PreApplicationStartMethodWebActivatorEx.ApplicationShutdownMethodAttribute

此外,旧的Ninject.Web.Common程序集提供了几个用于初始化的有用类--Bootstrapper,OnePerRequestHttpModule,NinjectHttpModule:

public static void Start()
{
    DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
    DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
    Bootstrapper.Initialize(CreateKernel);
}

问题:有没有关于如何将Ninject集成到ASP.NET Core 2.0 Web应用程序中的示例?

ninject asp.net-core-2.0
1个回答
16
投票

简短回答:

检查this project。但是,它依赖于仍然处于测试版的Ninject 4.0.0,它似乎远不是最终版本(source)。对于Ninject 3.3.x,请看下面。

答案很长:

感谢@Steven,我设法创建了一个ASP.NET Core 2.0和Ninject(3.3.x和4.0)的工作解决方案。代码主要来自Missing-Core-DI-Extensions Git repo,非常感谢dotnetjunkie

无论引用的Ninject版本如何,都必须执行以下操作:

1)在项目中包含AspNetCoreExtensions.csAspNetCoreMvcExtensions.cs

2)创建一个非常简单的服务来测试DI:TestService实现ITestService

public class TestService : ITestService
{
    public int Data { get; private set; }

    public TestService()
    {
        Data = 42;
    }
} 

public interface ITestService
{
    int Data { get; }
}

Ninject 3.3.x

如下所示更改Startup.cs

1)添加这些成员

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)加入ConfigureServices(IServiceCollection services)(最后)

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

services.AddRequestScopingMiddleware(() => scopeProvider.Value = new Scope());
services.AddCustomControllerActivation(Resolve);
services.AddCustomViewComponentActivation(Resolve);

3)添加到Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)(开头)

Kernel = RegisterApplicationComponents(app, loggerFactory);

4)添加以下方法和内部类:

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)创建BindToMethod扩展方法

public static class BindingHelpers
{
    public static void BindToMethod<T>(this IKernel config, Func<T> method) => 
        config.Bind<T>().ToMethod(c => method());
}

6)通过将自定义服务注入控制器,将断点设置为测试服务构造函数并检查调用堆栈来测试DI。除了提供一个实例,调用堆栈应该点击自定义代码来集成Ninject(例如ConfigureRequestScoping方法)

Ninject 4.0.0

IKernel在版本4中已被弃用,因此应该使用IReadOnlyKernel和IKernelConfiguration类(尽管上面的代码应该可以工作)。

1)使用新类(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)是一样的

4)方法略有不同:

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)扩展必须使用IKernelConfiguration

public static class BindingHelpers
{
    public static void BindToMethod<T>(
        this IKernelConfiguration config, Func<T> method) =>
            config.Bind<T>().ToMethod(c => method());
}
© www.soinside.com 2019 - 2024. All rights reserved.