【问题标题】:How to integrate Ninject into ASP.NET Core 2.0 Web applications?如何将 Ninject 集成到 ASP.NET Core 2.0 Web 应用程序中?
【发布时间】:2017-10-11 16:30:24
【问题描述】:

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

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

查看旧 ASP.NET MVC 解决方案的代码,我意识到整个机制与经典机制不同,因为经典机制依赖于 ASP.NET Core 中不再可用的 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 集成的示例:github.com/dotnetjunkie/Missing-Core-DI-Extensions/blob/master/…
  • @Steven - 我也找到了这个例子并尝试使用它,但因为它使用了一些我找不到的类型而被卡住了:ScopeIReadOnlyKernel 。上次提交是在大约 1 年前完成的,因此它可能与当前稳定版本的 Ninject (3.3.0) 和/或 ASP.NET Core (2.0) 不兼容。
  • 您需要使用Ninject 4.0 来处理这些示例,或者进行一些小的更改以使其与 Ninject 3.3 一起使用。这些示例使用 Ninject 4,因为 Ninject 3 与 .NET Standard 不兼容。
  • @Steven - 最新稳定版本 (3.3.1) 将 .NET Standard 2.0 列为依赖项,可以安装在 .NET Core 2.0 项目中。

标签: ninject asp.net-core-2.0


【解决方案1】:

简答:

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

【讨论】:

  • Step 3) 缺少实际需要添加到Configure(..) 方法的代码,我假设它是Kernel = RegisterApplicationComponents(app, loggerFactory);
  • @zeroid - 它确实不见了。修复。谢谢。很高兴有更多的程序员喜欢 Ninject 并尝试在 ASP.NET Core 中使用。
  • @Alexei:AspNetCoreMvcExtensions 中有一行无法编译:applicationTypeSelector = applicationTypeSelector ?? (type =&gt; !type.GetTypeInfo().Namespace.StartsWith("Microsoft")); 有什么想法吗?它正在尝试将?? 应用于Predicate&lt;Type&gt; 和一个lambda 表达式。
  • @zimdanen - 我签入了我的项目,它似乎可以工作。我正在使用目标框架 = .NET Core 2.0。你的目标框架是什么?另外,您使用的是 Visual Studio 2017 吗?
  • @zimdanen - 除了在 StackOverflow 上发布问题之外,我没有其他建议。只需确保包含整个函数体即可。
猜你喜欢
  • 2021-02-22
  • 1970-01-01
  • 1970-01-01
  • 2012-06-25
  • 2017-03-19
  • 2020-02-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多