30 votes

Erreur «Plusieurs liaisons correspondantes sont disponibles» lors de l'utilisation de Ninject.Web.Mvc 2.0 et ASP.NET MVC 1.0

Récemment, je suis passé à Ninject de la version 2.0 et commencé à recevoir le message d'erreur suivant:

Erreur: Erreur lors de l'activation SomeController
Plus d'une correspondance de fixations sont disponibles.
Chemin d'Activation:
 1) Demande de SomeController

Suggestions:
 1) vérifiez que vous avez défini une liaison pour SomeController qu'une seule fois.

Cependant, je ne suis pas en mesure de trouver certains de reproduction chemin. Parfois, il se produit, parfois ça ne marche pas. Je suis à l'aide d' NinjectHttpApplication automatique de contrôleurs de l'injection. Les contrôleurs sont définies en assemblée distincte:

public class App : NinjectHttpApplication
{
    protected override IKernel CreateKernel()
    {
        INinjectModule[] modules = new INinjectModule[] {
            new MiscModule(),
            new ProvidersModule(),
            new RepositoryModule(),
            new ServiceModule()
        };

        return new StandardKernel(modules);
    }

    protected override void OnApplicationStarted()
    {
        RegisterRoutes(RouteTable.Routes);
        RegisterAllControllersIn("Sample.Mvc");
        base.OnApplicationStarted();
    }

    /* ............. */

}

Peut-être quelqu'un est familier avec cette erreur.

Tous les conseils?

23voto

Aaron Ramirez Points 238

J'ai enfin compris ce problème récemment. Apparemment, le NinjectHttpApplication.RegisterAllControllersIn() la fonction n'a pas à faire de la bonne fixations nécessaires. Il se lie votre béton contrôleur des implémentations IController demandes. Par exemple, si vous avez un contrôleur de classe appelé SampleMvcController, qui hérite de System.Web.Mvc.Le contrôleur. Il ferait la suite nommé la liaison au cours de démarrage de l'application:

kernel.Bind<IController>().To(SampleMvcController).InTransientScope().Named("SampleMvc");

Mais lors du débogage de l'NinjectControllerFactory, je trouve que la demande pour le Noyau Ninject pour retourner un objet de la classe "SampleMvcController", pas pour une mise en œuvre concrète de IController, en utilisant le nom de la liaison de "SampleMvc".

De ce fait, lors de la première demande web qui implique la SampleMvcController est fait, il crée une liaison de SampleMvcController à lui-même. Ce n'est pas thread-safe si. Donc, si vous avez plusieurs web demandes à la fois, les liaisons peuvent potentiellement se produire plus d'une fois, et maintenant vous êtes de gauche avec cette erreur pour avoir plusieurs liaisons pour les SampleMvcController.

Vous pouvez le vérifier rapidement l'actualisation d'un MVC URL, juste après la cause de votre application web pour redémarrer.

Le correctif:

La façon la plus simple de résoudre ce problème est de créer un nouveau NinjectModule pour votre contrôleur de liaisons, et le chargement de ce module de cours de démarrage de l'application. Dans ce module, vous auto lier chacun de vos contrôleurs, comme suit:

class ControllerModule : StandardModule {
      public override Load() {
        Bind<SampleMvcController>().ToSelf();
        Bind<AnotherMvcController>().ToSelf();
      }
    }

Mais si vous n'avez pas l'esprit de la modification de la Ninject code source, vous pouvez modifier la RegisterAllControllersIn() la fonction d'auto lier chaque contrôleur de il vient à travers.

16voto

Steve Hook Points 767

J'ai eu affaire à ce problème depuis des mois. J'ai essayé de nombreuses options, mais ne parvient pas à trouver une solution. Je savais que c'était un filetage problème, car il ne pourrait se produire que lorsqu'il y a une lourde charge sur mon site. Tout récemment, un bug a été signalé et corrigé dans la ninject code source qui permet de résoudre ce problème.

Ici est une référence à la question. Il a été fixé dans le build 2.1.0.70 de la Ninject source. Le changement majeur a été dans KernelBase.cs par la suppression de la ligne

context.Plan = planner.GetPlan(service);

et de le remplacer avec

lock (planner)
{
    context.Plan = planner.GetPlan(service);
}

Pour utiliser cette nouvelle version avec MVC, vous aurez besoin pour obtenir la dernière version de Ninject puis obtenir la dernière version de ninject.web.mvc. Construire ninject.web.mvc avec la nouvelle Ninject construire.

J'ai été en utilisant ce nouveau construire pour environ une semaine avec une lourde charge, pas de problèmes. C'est la plus longue, elle a disparu sans problème donc je ne considère pas que cela soit une solution.

1voto

Ruben Bartelink Points 23945

Êtes-vous sûr de vraiment créer un seul Kernel entièrement nouveau à partir de zéro dans votre OnApplicationStarted chaque fois qu'il est invoqué? Si vous ne l'êtes pas et que vous le créez en réalité une fois, mais que vous exécutez potentiellement le bit d'enregistrement deux fois. N'oubliez pas qu'il n'est pas garanti de ne jamais avoir qu'une seule classe App instanciée dans un AppDomain donné.

1voto

msteel9999 Points 68

Ma réponse était un peu plus évidente.

J'avais déclaré la liaison pour l'un de mes contrôleurs plus d'une fois lors de la refactorisation de mon code.

0voto

coalvilledave Points 860

J'ai ajouté ceci à mon fichier global.ascx.cs:

         public void RegisterAllControllersInFix(Assembly assembly)
    {
        RegisterAllControllersInFix(assembly, GetControllerName);
    }

    public void RegisterAllControllersInFix(Assembly assembly, Func<Type, string> namingConvention)
    {
        foreach (Type type in assembly.GetExportedTypes().Where(IsController))
            Kernel.Bind(type).ToSelf();
    }

    private static bool IsController(Type type)
    {
        return typeof(IController).IsAssignableFrom(type) && type.IsPublic && !type.IsAbstract && !type.IsInterface;
    }

    private static string GetControllerName(Type type)
    {
        string name = type.Name.ToLowerInvariant();

        if (name.EndsWith("controller"))
            name = name.Substring(0, name.IndexOf("controller"));

        return name;
    }
 

Ensuite, je l'ai appelé depuis ma méthode OnApplicationStarted () comme suit:

         RegisterAllControllersIn(Assembly.GetExecutingAssembly());
        RegisterAllControllersInFix(Assembly.GetExecutingAssembly());
 

Difficile de savoir si cela l'a corrigé, car c'est tellement intermittent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X