web-dev-qa-db-fra.com

MVC5, Web API 2 et Ninject

J'ai créé un nouveau projet MVC5 avec Web API 2, puis j'ai ajouté le package Ninject.MVC3 de NuGet.

L'injection de constructeur fonctionne correctement pour les contrôleurs MVC5, mais j'obtiens une erreur en essayant de l'utiliser avec les contrôleurs API Web.

Une erreur s'est produite lors de la tentative de création d'un contrôleur de type 'UserProfileController'. Assurez-vous que le contrôleur a un constructeur public sans paramètre.

Constructeur pour contrôleur MVC5 actif:

public class HomeController : Controller
{
    private IMailService _mail;
    private IRepository _repo;

    public HomeController(IMailService mail, IRepository repo)
    {
        _mail = mail;
        _repo = repo;
    }
}

Constructeur pour le contrôleur API Web qui ne fonctionne pas:

public class UserProfileController : ApiController
{
    private IRepository _repo;

    public UserProfileController(IRepository repo)
    {
        _repo = repo;
    }
}

Ci-dessous se trouve le fichier NinjectWebCommon.cs complet:

[Assembly: WebActivator.PreApplicationStartMethod(typeof(DatingSite.App_Start.NinjectWebCommon), "Start")]
[Assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(DatingSite.App_Start.NinjectWebCommon), "Stop")]

namespace DatingSite.App_Start
{
using System;
using System.Web;

using Microsoft.Web.Infrastructure.DynamicModuleHelper;

using Ninject;
using Ninject.Web.Common;
using DatingSite.Services;
using DatingSite.Data;

public static class NinjectWebCommon
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start()
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
#if DEBUG
        kernel.Bind<IMailService>().To<MockMailService>().InRequestScope();

#else
        kernel.Bind<IMailService>().To<MailService>().InRequestScope();
#endif
        kernel.Bind<SiteContext>().To<SiteContext>().InRequestScope();
        kernel.Bind<IRepository>().To<Repository>().InRequestScope();
    }
}
}
70
Declan

Le package package de Ninject.Web.WebApi NuGet vient de paraître. À partir de maintenant, la solution préférée consiste à utiliser ce package . Je ne trouvais aucune documentation connexe, mais après avoir installé le package, tout a fonctionné pour moi.

Install-Package Ninject.Web.WebApi 

Après l'installation, les instances normales de contrôleur MVC et d'API sont fournies par Ninject.

Si Ninject.Web.Common est déjà installé, veillez à enregistrer vos liaisons à partir de NinjectWebCommon.cs et à laisser Nuget réécrire NinjectWebCommon.cs lors de l'installation et à remettre vos liaisons à la fin.

Comme indiqué dans les commentaires en fonction de votre contexte d'exécution, vous aurez besoin un des paquets suivants aussi:

  • Ninject.Web.WebApi.WebHost
  • Ninject.Web.WebApi.OwinHost
  • Ninject.Web.WebApi.Selfhost

Le scénario le plus courant est IIS pour choisir le package WebHost.

Dans le cas où vous démarrez une application Web IIS MVC5 à partir de zéro et souhaitez utiliser Ninject, installez les packages suivants:

  • Ninject - Ninject core dll
  • Ninject.Web.Common - Fonctionnalité Web commune pour Ninject, par exemple. InRequestScope ()
  • Ninject.MVC5 - injecteurs de dépendance MVC, par exemple. fournir des contrôleurs pour MVC
  • Ninject.Web.Common.WebHost - Enregistre les injecteurs de dépendance à partir de Ninject.MVC5 lorsque IIS démarre l'application Web. Si vous n'utilisez pas IIS, vous aurez besoin d'un autre package, vérifiez ci-dessus.
  • Ninject.Web.WebApi Injecteurs de dépendance WebApi, par exemple. fournir des contrôleurs pour WebApi
  • Ninject.web.WebApi.WebHost - Enregistre les injecteurs de dépendance à partir de Ninject.Web.WebApi lorsque IIS démarre l'application Web.
102
Hari

Vous avez ce problème car Controller et ApiController utilisent des résolveurs de dépendance différents. La solution est très simple.

Dans un premier temps, créez de nouvelles classes de résolution de dépendance et de portée de dépendance. Vous pouvez utiliser ceci:

 public class NinjectResolver : NinjectScope, IDependencyResolver
{
    private readonly IKernel _kernel;
    public NinjectResolver(IKernel kernel)
        : base(kernel)
    {
        _kernel = kernel;
    }
    public IDependencyScope BeginScope()
    {
        return new NinjectScope(_kernel.BeginBlock());
    }
}

public class NinjectScope : IDependencyScope
{
    protected IResolutionRoot resolutionRoot;
    public NinjectScope(IResolutionRoot kernel)
    {
        resolutionRoot = kernel;
    }
    public object GetService(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).SingleOrDefault();
    }
    public IEnumerable<object> GetServices(Type serviceType)
    {
        IRequest request = resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
        return resolutionRoot.Resolve(request).ToList();
    }
    public void Dispose()
    {
        IDisposable disposable = (IDisposable)resolutionRoot;
        if (disposable != null) disposable.Dispose();
        resolutionRoot = null;
    }
}

Après cela, ajoutez la ligne suivante à la méthode CreateKernel () dans NinjectWebCommon

 GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
38
Artur Movsesyan

J'ai eu le même problème ... après l'installation des paquets NuGet suivants:

  • Ninject 
  • Ninject.web.WebApi 
  • Ninject.web.WebApi.WebHost
  • Ninject.MVC3
  • Ninject.web.Common 
  • Ninject.web.Common.WebHost

tout fonctionne bien

29
Oleg

Je trouve que Assembly Ninject.Web.WebApi.dll définit son propre DependencyResolver et l'enregistre avec le noyau dans la classe Ninject.Web.WebApi.WebApiModule automatiquement.

J'ajoute donc simplement à NinjectWebCommon.CreateKernel une ligne ...

GlobalConfiguration.Configuration.DependencyResolver = 
    kernel.Get<System.Web.Http.Dependencies.IDependencyResolver>();

Enfin, mon projet a les dépendances suivantes:

  • Ninject 3.2.0
  • Ninject.Web.Common 3.2.0
  • Ninject.Web.WebApi 3.2.4
24
user1295211

Juste pour les autres, qui ont peut-être une configuration similaire à moi, et qui sont arrivés ici via Google comme je l’ai fait.

J'ai eu plusieurs applications utilisant un projet WebApi. J'obtiendrais l'erreur ci-dessus si je n'avais pas inclus la liaison dans la méthode RegisterServices. Avant de vous arracher les cheveux, vérifiez que la fixation est bien en place. L'erreur ne vous dit pas qu'il vous manque des liaisons. Ce qui serait le cas si l'application est dans le même projet que WebApi.

3
Richard France

J'ai eu ce problème dans une solution où le projet dans lequel j'utilisais Ninject n'utilisait pas l'API Web (j'ai déjà 6 projets dans ma solution). Je continuais à obtenir le redouté "constructeur sans paramètre requis", ce qui voulait évidemment dire que lorsque je l'ai ajouté, l'injection de Ninject n'était pas instanciée car elle tombait dans le constructeur vide. J'ai essayé diverses solutions, mais au final, j'ai vérifié mes paquets Ninject et constaté que le paquet Ninject.Web.Webapi était installé. J'ai désinstallé ceci et fait un nettoyage et une reconstruction. Cela a résolu le problème. Mon autre projet de niveau inférieur faisait référence au paquet Ninject.Web.Api et, bêtement, je l'avais installé dans mon projet Web frontal. 

J'espère que cela pourra aider d'autres personnes qui ont essayé toutes les solutions Stack et qui ne sont pas allées où.

0
Mike Cave

J'ai récemment dû utiliser Web Api 2 pour pouvoir répondre à cette partie de la question.

Ce sont les packages de nuget nécessaires pour Web Api 2- 

Ninject
Ninject.Web.Common
Ninject.Web.Common.WebHost
Ninject.Web.WebApi 
WebActivatorEx 

Puis éditez NinjectWebCommon.CreateKernel(..) y compris 

RegisterServices(kernel);
// the next line is the important one
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
return kernel;

J'ai écrit un article plus détaillé à ce sujet - http://NoDogmaBlog.bryanhogan.net/2016/04/web-api-2-and-ninject-how-tmake-them-work-together/ incluant une solution complète à télécharger.

0
Bryan