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

标签 ninject asp.net-core-2.0

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

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

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

另外,旧的 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 应用程序中的示例?

最佳答案

简短的回答:

查看this project .但是,它依赖于仍处于 beta 版本的 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) 通过将自定义服务注入(inject) Controller 、在测试服务构造函数中设置断点并检查调用堆栈来测试 DI。除了提供实异常(exception),调用堆栈还应命中自定义代码以集成 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());
}

关于ninject - 如何将 Ninject 集成到 ASP.NET Core 2.0 Web 应用程序中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46693305/

相关文章:

asp.net-web-api - 如何将对象参数传递给 web api 中的 get 方法?

c# - 在 C# 中使用 CaSTLe Windsor 自绑定(bind)

asp.net-mvc - Ninject 和连接字符串

asp.net-mvc-3 - ASP.NET MVC 3 和全局过滤器注入(inject)

c# - TransactionScope 不会在使用 NUnit 和 TestServer 进行集成测试的每次测试 TearDown 中回滚

asp.net-core-2.0 - asp.net 核心身份 - Id 列是 nvarchar(450) - 为什么?

wcf - 如何替代使用 Wcf 合约的接口(interface)

c# - 将多个 EF 上下文注册到一个 DI 容器中

asp.net-core-2.0 - IdentityServer4 签名 key 、验证 key 和 .Net Core 数据保护

c# - 是否有与旧 WebApi IHttpControllerTypeResolver 等效的 AspNetCore?