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

2024-02-09

我发现 Ninject 最近引入了对 .NET Standard 2.0 / .NET Core 2.0 的支持 https://www.nuget.org/packages/Ninject/3.3.0.

但是,我找不到任何扩展来将其实际集成到 Web 应用程序中(例如类似于Ninject.Web.Common https://www.nuget.org/packages/Ninject.Web.Common/)

查看旧的 ASP.NET MVC 解决方案中的代码,我意识到整个机制与经典机制所依赖的不同WebActivatorEx.PreApplicationStartMethod and WebActivatorEx.ApplicationShutdownMethodAttribute它们在 ASP.NET Core 中不再可用。

还有,老Ninject.Web.Commonassembly 提供了几个用于初始化的有用类 - 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 应用程序中的示例?


简短回答:

check 这个项目 https://github.com/dotnetjunkie/Missing-Core-DI-Extensions/blob/master/src/SampleApplication.Ninject/Startup.cs。然而,它依赖于 Ninject 4.0.0,该版本仍处于测试版本,似乎距离最终版本还很远(source https://stackoverflow.com/questions/38261521/ninject-in-net-core/46521359#46521359)。对于 Ninject 3.3.x,请参见下文。

长答案:

谢谢@Steven我成功创建了 ASP.NET Core 2.0 和 Ninject(3.3.x 和 4.0)的工作解决方案。代码主要来自缺少核心 DI 扩展 https://github.com/dotnetjunkie/Missing-Core-DI-Extensions/blob/master/src/SampleApplication.Ninject/Startup.csGit 存储库,非常感谢点网迷 https://github.com/dotnetjunkie.

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

1) 包括AspNetCore 扩展.cs https://github.com/dotnetjunkie/Missing-Core-DI-Extensions/blob/master/src/MissingDIExtensions/AspNetCoreExtensions.cs and AspNetCoreMvcExtensions.cs https://github.com/dotnetjunkie/Missing-Core-DI-Extensions/blob/master/src/MissingDIExtensions/AspNetCoreMvcExtensions.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; }
}

忍者3.3.x https://www.nuget.org/packages/Ninject/4.0.0-beta-0134

Change 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 method)

忍者4.0.0 https://www.nuget.org/packages/Ninject/4.0.0-beta-0134

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());
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 Ninject 集成到 ASP.NET Core 2.0 Web 应用程序中? 的相关文章

随机推荐