首页 文章

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

提问于
浏览
8

我发现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);
}

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

1 回答

  • 13

    简答:

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

相关问题