web-dev-qa-db-ja.com

NinjectをASP.NET Core 2.0 Webアプリケーションに統合する方法は?

私はNinjectが最近 。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アプリケーションに統合する方法の例はありますか?

13
Alexei

簡潔な答え:

チェック このプロジェクト 。ただし、それはまだベータ版である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リポジトリからのものです。 dotnetjunkie に感謝します。

参照されているNinjectのバージョンに関係なく、以下を実行する必要があります。

1)プロジェクトに AspNetCoreExtensions.cs および 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; }
}
_

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.

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());
}
_
17
Alexei