web-dev-qa-db-fra.com

Comment intégrer Ninject dans des applications Web ASP.NET Core 2.0?

J'ai découvert que Ninject a récemment introduit la prise en charge de .NET Standard 2.0/.NET Core 2. .

Cependant, je ne trouve aucune extension pour l'intégrer réellement dans l'application Web (par exemple similaire à Ninject.Web.Common )

En regardant le code d'une ancienne solution ASP.NET MVC, j'ai réalisé que tout le mécanisme est différent car le classique s'appuyait sur WebActivatorEx.PreApplicationStartMethod et WebActivatorEx.ApplicationShutdownMethodAttribute qui ne sont plus disponibles dans ASP.NET Core.

En outre, l'ancien Ninject.Web.Common L'assembly a fourni plusieurs classes utiles utilisées pour l'initialisation - Bootstrapper, OnePerRequestHttpModule, NinjectHttpModule:

public static void Start()
{
    DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
    DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
    Bootstrapper.Initialize(CreateKernel);
}

Question: existe-t-il un exemple de la façon d'intégrer Ninject dans une application Web ASP.NET Core 2.0?

13
Alexei

Réponse courte:

check ce projet . Cependant, il s'appuie sur Ninject 4.0.0 qui est toujours en version bêta et il semble loin d'être une version finale ( source ). Pour Ninject 3.3.x, regardez ci-dessous.

Longue réponse:

Grâce à @Steven, J'ai réussi à créer une solution de travail d'ASP.NET Core 2.0 et Ninject (3.3.x et 4.0). Le code provient principalement de Missing-Core-DI-Extensions Git repo, donc super grâce à dotnetjunkie .

Les opérations suivantes doivent être effectuées quelle que soit la version de Ninject référencée:

1) Inclure AspNetCoreExtensions.cs et AspNetCoreMvcExtensions.cs dans votre projet.

2) Créez un service très simple à utiliser pour tester la DI: TestService qui implémente 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

Modifiez Startup.cs Comme indiqué ci-dessous:

1) ajouter ces membres

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) Ajouter à ConfigureServices(IServiceCollection services) (à la fin)

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

services.AddRequestScopingMiddleware(() => scopeProvider.Value = new Scope());
services.AddCustomControllerActivation(Resolve);
services.AddCustomViewComponentActivation(Resolve);

3) Ajouter à Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) (au début)

Kernel = RegisterApplicationComponents(app, loggerFactory);

4) Ajoutez la méthode et la classe interne suivantes:

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) Créer une méthode d'extension BindToMethod

public static class BindingHelpers
{
    public static void BindToMethod<T>(this IKernel config, Func<T> method) => 
        config.Bind<T>().ToMethod(c => method());
}

6) Testez DI en injectant un service personnalisé dans un contrôleur, en définissant un point d'arrêt dans le constructeur du service de test et en vérifiant la pile d'appels. En plus de fournir une instance, la pile d'appels doit frapper du code personnalisé pour intégrer Ninject (par exemple la méthode ConfigureRequestScoping)

Ninject 4.0.

IKernel a été déconseillé dans la version 4, donc les classes IReadOnlyKernel et IKernelConfiguration doivent être utilisées (bien que le code ci-dessus devrait fonctionner).

1) Utilisez la nouvelle classe (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) sont les mêmes

4) La méthode est légèrement différente:

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) L'extension doit utiliser un IKernelConfiguration

public static class BindingHelpers
{
    public static void BindToMethod<T>(
        this IKernelConfiguration config, Func<T> method) =>
            config.Bind<T>().ToMethod(c => method());
}
17
Alexei