web-dev-qa-db-fra.com

Ninject dans ASP.NET MVC4

Donc, après beaucoup de bêtises, Ninject a finalement été câblé et compilé dans mon application MVC4. Le problème que je rencontrais est que l'interface IDependencyScope n'existe plus de ce que je peux dire et que l'espace de noms System.Web.Http.Dependencies a été supprimé.

Donc, le problème, c’est que j’ai tout connecté et que j’obtiens lors de l’exécution de l’application:

    Sequence contains no elements

    [InvalidOperationException: Sequence contains no elements]
   System.Linq.Enumerable.Single(IEnumerable`1 source) +379
   Ninject.Web.Mvc.NinjectMvcHttpApplicationPlugin.Start() in c:\Projects\Ninject\ninject.web.mvc\mvc3\src\Ninject.Web.Mvc\NinjectMvcHttpApplicationPlugin.cs:53
   Ninject.Web.Common.Bootstrapper.<Initialize>b__0(INinjectHttpApplicationPlugin c) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:52
   Ninject.Infrastructure.Language.ExtensionsForIEnumerableOfT.Map(IEnumerable`1 series, Action`1 action) in c:\Projects\Ninject\ninject\src\Ninject\Infrastructure\Language\ExtensionsForIEnumerableOfT.cs:31
   Ninject.Web.Common.Bootstrapper.Initialize(Func`1 createKernelCallback) in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\Bootstrapper.cs:53
   Ninject.Web.Common.NinjectHttpApplication.Application_Start() in c:\Projects\Ninject\Ninject.Web.Common\src\Ninject.Web.Common\NinjectHttpApplication.cs:81

Ce que je n'ai pas été capable de localiser ni même de commencer à comprendre d'où cela vient.

Mes méthodes Ninject standard dans Global.asax.cs se présentent comme suit:

        protected override IKernel CreateKernel()
        {
            var kernel = new StandardKernel();
            kernel.Load(Assembly.GetExecutingAssembly());
            kernel.Bind<IRenderHelper>().To<RenderHelper>();

            GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NinjectDependencyResolver(kernel));
            return kernel;
        }

        protected override void OnApplicationStarted()
        {
            base.OnApplicationStarted();
            AreaRegistration.RegisterAllAreas();
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
            BundleTable.Bundles.RegisterTemplateBundles();
        }

Et mon résolveur personnalisé:

public class NinjectDependencyResolver : IDependencyResolver
{
    private readonly IKernel _kernel;

    public NinjectDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    public object GetService(Type serviceType)
     {
         return _kernel.TryGet(serviceType);
     }

     public IEnumerable<object> GetServices(Type serviceType)
     {
         try
         {
             return _kernel.GetAll(serviceType);
         }
         catch (Exception)
         {
             return new List<object>();
         }
     }

     public void Dispose()
     {
         // When BeginScope returns 'this', the Dispose method must be a no-op.
     }
}

Toute idée ici serait grandement appréciée. J'ai déjà passé beaucoup trop de temps à essayer de brancher une infrastructure DI dans le dernier MVC4 RC fonctionnant sous .NET 4.5 et je viens d'atteindre mon niveau de tolérance pour des problèmes qui ne fonctionnent tout simplement pas. 

Edit # 1 Un peu de recherche plus loin dans github le ExtensionsForIEnumerableOfT.cs n'aide pas beaucoup:

https://github.com/ninject/ninject/blob/master/src/Ninject/Infrastructure/Language/ExtensionsForIEnumerableOfT.cs

Et éventuellement, si je l'avais écrit moi-même, je commencerais à comprendre cela, mais Bootstrapper.cs n'aide pas beaucoup non plus.

https://github.com/ninject/Ninject.Web.Common/blob/master/src/Ninject.Web.Common/Bootstrapper.cs

En espérant que ces détails faciliteront la tâche de ceux qui ont déjà une expérience accrue de Ninject.

Edit # 2 L'erreur rencontrée est spécifiquement dans NinjectMvcHttpApplicationPlugin.cs:

La ligne incriminée est:

ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());

Qui vit dans la méthode suivante:

public void Start()
{
    ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
    DependencyResolver.SetResolver(this.CreateDependencyResolver());
    RemoveDefaultAttributeFilterProvider();
}

La collection ModelValidatorProviders contient 2 éléments: {System.Web.Mvc.DataErrorInfoModelValidatorProvider} {System.Web.Mvc.ClientDataTypeModelValidatorProvider}

Et il essaie de supprimer une seule instance de:

System.Web.Mvc.DataAnnotationsModelValidatorProvider

Ce qui apparemment n'est pas chargé dans la collection ModelValidationProviders.Providers. Des idées d'ici?

Résolution à l'exception et à la suivante

Pour résoudre le problème dans ModelValidatorProviders, je devais ajouter manuellement un objet attendu. Alors maintenant, ma méthode CreateKernel ressemble à:

protected override IKernel CreateKernel()
{
    var kernel = new StandardKernel();
    kernel.Load(Assembly.GetExecutingAssembly());

    kernel.Bind<IRenderHelper>().To<RenderHelper>();
    kernel.Unbind<IDocumentViewerAdapter>();

    GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NinjectDependencyResolver(kernel));
    ModelValidatorProviders.Providers.Add(new DataAnnotationsModelValidatorProvider());
    FilterProviders.Providers.Add(new FilterAttributeFilterProvider());
    return kernel;
}

Maintenant, il fonctionne et entre dans les tripes de Ninject mais a toujours un problème, qui n'a plus de sens:

Exception Details: Ninject.ActivationException: Error activating IntPtr
No matching bindings are available, and the type is not self-bindable.
Activation path:
 3) Injection of dependency IntPtr into parameter method of constructor of type Func{IKernel}
 2) Injection of dependency Func{IKernel} into parameter lazyKernel of constructor of type HttpApplicationInitializationHttpModule
 1) Request for IHttpModule

Suggestions:
 1) Ensure that you have defined a binding for IntPtr.
 2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
 3) Ensure you have not accidentally created more than one kernel.
 4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
 5) If you are using automatic module loading, ensure the search path and filters are correct.
20
VulgarBinary

Ok, après avoir frappé ma tête contre le mur pendant trop longtemps, j'ai compris ce qui se passait. Le type de projet par défaut pour MVC4 s'exécutant sur .NET 4.5 comportait une référence à la version RC d'origine de System.Web.Http au lieu de la version mise à jour.

Les espaces de noms manquaient, les objets n'existaient pas, la vie n'était pas bonne. 

Étapes à suivre pour la résolution:

  1. Supprimez votre référence à System.Web.Http dans votre projet MVC4
  2. Ajouter une référence -> System.Web.Http
  3. Supprimez tous les contournements que vous avez mis en place pour que l'ancienne version usée de System.Web.Http fonctionne
  4. Réappliquez le processus standard pour câbler dans Ninject.

    CEPENDANT, l'erreur de:

    Détails des exceptions: Ninject.ActivationException: erreur lors de l'activation de IntPtrAucune liaison correspondante n'est disponible, et le type n'est pas auto-affectable. 3) Injection de la dépendance IntPtr dans la méthode de paramètre du constructeur de type Func {IKernel} 2) Injection de la dépendance Func {IKernel} dans le paramètre lazyKernel du constructeur de type HttpApplicationInitializationHttpModule 1) Demande de IHttpModule

    Suggestions: 1) Assurez-vous que vous avez défini une liaison pour IntPtr . 2) Si la liaison a été définie dans un module, assurez-vous que le module a été chargé dans le noyau . 3) Assurez-vous de ne pas avoir créé accidentellement plus d’un noyau . 4) Si vous utilisez des arguments de constructeur, assurez-vous que le nom du paramètre correspond au nom du paramètre de constructeur . 5) Si vous utilisez le chargement automatique de module, assurez-vous que le chemin de recherche et les filtres sont corrects.

Update Ceci a été résolu en mettant à jour MVC de MVC4 Beta à MVC4 RC.

18
VulgarBinary

Consultez le livre Pro ASP.NET MVC 3 book . Je viens de transférer ce code de MVC3 à MVC4 hier soir et cela fonctionne correctement. Page 322 pour être exact. 

Ce que je ne vois pas, c'est où vous mappez votre interface avec vos éléments concrets. 

Bind<ISomething>().To<Something>();

Ajoutez un autre constructeur et ajoutez la méthode qui appelle votre mappage.

public NinjectDependencyResolver() {
    _kernal = new StandardKernel();
    RegisterServices(_kernel);
}

public static void RegisterServices(IKernel kernel) {
    kernel.Bind<ISomething>().To<Something>();
}

Voici à quoi un résolveur pourrait/devrait ressembler;

   public class NinjectDependencyResolver : IDependencyResolver {
    private IKernal _kernel;

    public NinjectDependencyResolver(){
        _kernal = StandardKernal();
        AddBindings();
    }

    public NinjectDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    public object GetService(Type serviceType)
     {
         return _kernel.TryGet(serviceType);
     }

     public IEnumerable<object> GetServices(Type serviceType)
     {
        return _kernal.GetAll(serviceType);
     }

    public IBindingToSyntax<T> Bind<T>() {
      return _kernal.Bind<T>();
    }

     public static void RegisterServices(IKernel kernel){
      //Add your bindings here. 
      //This is static as you can use it for WebApi by passing it the IKernel
     }
}

Global.Asx -

Application_Start ()

méthode

DependencyResolver.SetResolver(new NinjectDependencyResolver());

C'est tout.


MIS À JOUR 14/11/2012

En passant, si vous travaillez avec MVC WebAPI, vous voudrez utiliser WebApiContrib.IoC.Ninject from nuget. En outre, consultez le "Gestionnaire de contacts" dans leurs exemples asp.net.com . Cela a aidé à nettoyer la mise en œuvre de Ninject 

5
anAgent

Supprimez simplement le fichier NinjectWebCommon.cs de votre projet (il se trouve dans le dossier App_Start). et tout devrait fonctionner.

Source: http://mlindev.blogspot.com.au/2012/09/how-to-implement-dependency-injection.html

4
1_bug

Lorsque vous installez le dernier package Ninject.MVC3 de NuGet, nous trouvons le code suivant par-dessus le fichier NinjectWebCommon.cs:

[Assembly: WebActivator.PreApplicationStartMethod(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Start")]

[Assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(MvcApplication1.App_Start.NinjectWebCommon), "Stop")]

dans ce cas, nous n'avons pas besoin d'enregistrer explicitement ninject dans global.asax

J'ai trouvé un bon contenu sur l'utilisation de Ninject avec MVC 4 ici

1
user2035720

J'ai rencontré le même problème pas tout à fait sûr de ce qui a résolu après les modifications ci-dessous

ninject.MVC4 ajouté au projet

ninjectWebCommon.cs supprimé (le fichier généré, car l'intégration existe déjà dans le fichier global.ascx.cs)

0
Naga

J'utilise DD4T et j'ai rencontré la même erreur.

Après avoir vérifié que tous les packages sont installés par le gestionnaire de packages de nuget, J'ai constaté que certaines des DLL/références étaient manquantes (newtonsoft, etc.):

Puis, après avoir réinstallé Newtonsoft.Json (pour réinstaller le paquet, utilisez la commande suivante dans le Gestionnaire de paquets Nuget: Update-Package –reinstall Newtonsoft.Json), puis en plaçant netrtsn.dll dans Tridion Deployer bin, cette erreur s'est produite. ne contient aucun élément "avec exactement la même trace de pile que celle donnée dans cette question.

Merci à Naga d’avoir fourni cette résolution Supprimé NinjectWebCommon.cs (le fichier généré, car l’intégration existe déjà dans le fichier global.ascx.cs), et wohooooo !!!! toutes les erreurs résolues, Tridion + MVC4 = DD4T fonctionne correctement maintenant.

0

J'ai également eu ce problème lorsque j'ai utilisé Nuget pour installer Ninject.MVC4 dans un projet référencé par mon projet de site Web MVC actuel.

Le problème est que le fichier NinjectWebCommon.cs installé automatiquement dans le répertoire App_Start du projet référencé est en conflit avec celui (réel, utile) installé dans mon projet de site Web. Supprimer le fichier NinjectWebCommon.cs du projet référencé résout l'erreur.

0
fordareh

J'ai tendance à garder mon amorce Ninject dans un projet séparé. Afin d'utiliser la méthode d'extension .InRequestScope() de IBindingInSyntax<T>, j'avais ajouté via Nuget la bibliothèque Ninject.Web.Common . Hélas, cette bibliothèque inclut le bootstrapper app_start, ce qui entraîne la duplication des classes NinjectWebCommon et l’attachement via WebActivator (1 dans ledit projet et 1 dans le projet MVC lui-même). 

J'ai supprimé le dossier App_Start en double de mon projet d'amorçage et cela a résolu le problème.