2010-03-11 6 views
30

Recientemente he cambiado a Ninject 2.0 liberación y empecé a recibir el siguiente error:error "Más de un fijaciones de juego están disponibles" cuando se utiliza Ninject.Web.Mvc 2.0 y ASP.NET MVC 1.0

 
Error occured: Error activating SomeController 
More than one matching bindings are available. 
Activation path: 
    1) Request for SomeController 

Suggestions: 
    1) Ensure that you have defined a binding for SomeController only once. 

Sin embargo, no puedo encontrar cierta ruta de reproducción. A veces ocurre, a veces no ocurre. Estoy usando NinjectHttpApplication para la inyección de controladores automáticos. Los controladores se definen en un conjunto separado:

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

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

} 

Quizás alguien esté familiarizado con este error.

¿Algún consejo?

+0

FYI, no es exclusivo de ASP.NET MVC 1.0. Acabo de suceder en ASP.NET MVC 2.0 también. – mckamey

+2

Creé un proyecto repro para esta situación y lo cargué en el grupo Ninject-dev. Con suerte, alguien reconocerá el problema. No pude ver una solución fácil. http://groups.google.com/group/ninject-dev/files – mckamey

+0

FYI, he verificado que esto se solucionó en la versión 2.1.0.0 de NinjectNinject.Web.Mvc (MVC2). En la última versión, ya no es necesario llamar a RegisterAllControllersIn (...). – mckamey

Respuesta

23

Finalmente me di cuenta de este problema recientemente. Aparentemente, la función NinjectHttpApplication.RegisterAllControllersIn() no hace todos los enlaces necesarios. Vincula sus implementaciones concretas de controladores a las solicitudes de IController. Por ejemplo, si tiene una clase de controlador llamada SampleMvcController, que hereda de System.Web.Mvc.Controller. Se haría lo siguiente nombrado vinculante durante el inicio de la aplicación:

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

Pero cuando la depuración de la NinjectControllerFactory, me parece que la solicitud se están realizando para la Ninject Kernel para devolver un objeto de la clase "SampleMvcController", no para un hormigón implementación de IController, utilizando el enlace nombrado de "SampleMvc".

Debido a esto, cuando se realiza la primera solicitud web que implica el SampleMvcController, crea un enlace de SampleMvcController consigo mismo. Esto no es seguro para subprocesos. Por lo tanto, si tiene varias solicitudes web que se realizan a la vez, es posible que las vinculaciones ocurran más de una vez, y ahora le queda este error por tener enlaces múltiples para SampleMvcController.

Puede verificar esto actualizando rápidamente una URL de MVC, justo después de hacer que la aplicación web se reinicie.

La solución:

La forma más sencilla de solucionar este problema es crear una nueva NinjectModule para sus enlaces de controlador, y para cargar este módulo durante el inicio de la aplicación. Dentro de este módulo, se auto ates cada uno de los controladores definidos, así:

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

Pero si no te importa cambiar el código fuente Ninject, puede modificar la función RegisterAllControllersIn() para obligar a uno mismo cada controlador se viene a través de.

+1

Gracias por la pista. Lo intentaré y marcaré tu respuesta. ¿Ya le avisaste a Nate Kohari? =) –

+0

Gracias por esto, nos estábamos sacando de quicio con este problema. – DavidWhitney

1

¿Estás seguro de que realmente estás creando un nuevo Kernel completamente nuevo desde cero en tu OnApplicationStarted cada vez que se invoca? Si no lo está y en realidad lo está creando una vez, pero potencialmente puede ejecutar el bit de registro dos veces. Recuerde que no se garantiza que tenga una sola clase App instanciada nunca dentro de un Dominio de aplicación determinado.

+0

Eche un vistazo a README en la parte inferior de la página http://github.com/enkari/ninject.web.mvc (creo que mi código es bastante similar). Sin embargo, cuando miro al método NinjectHttpApplication Application_Start() http://github.com/enkari/ninject.web.mvc/blob/master/mvc1/src/Ninject.Web.Mvc/NinjectHttpApplication.cs me hace pensar que la configuración se hace por instancia de kernel único. –

+0

@Cray: voy a buscar a tiempo, lo siento, no tengo tiempo ahora pero quería responder en caso de que te desbloqueara. El punto principal de mi publicación es decir "esta excepción sugiere que pongas un conjunto duplicado o Vinculaciones en el kernel de alguna manera, tal vez inicializando dos veces en el mismo kernel", sin importar dónde hayas obtenido el código y sin importar si tu pregunta representa un reflejo preciso de su código real que está fallando. (He hecho cero con el RTM NI2 pero hay montones con varias compilaciones anteriores a la 2) –

0

he añadido esto a mi archivo 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; 
    } 

Entonces llamaron a mi método OnApplicationStarted() de la siguiente manera:

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

difícil saber si esto esté arreglado él sin embargo porque es muy intermitente.

+0

Pruebe algo como WebClient.DownloadString ("http: // yoursite /") en el bucle, ... en varios hilos =) –

+0

Lo haré - gracias Denis – coalvilledave

16

He estado lidiando con este problema durante meses. Intenté tantas opciones pero no pude llegar a una solución. Sabía que era un problema de subprocesamiento porque solo ocurriría cuando hubiera una gran carga en mi sitio. Recientemente se informó un error y se corrigió en el código fuente de ninject que resuelve este problema.

Aquí hay una referencia al issue. Se corrigió en la compilación 2.1.0.70 de la fuente Ninject. El cambio clave estaba en KernelBase.cs mediante la eliminación de la línea

context.Plan = planner.GetPlan(service); 

y su sustitución por

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

Para utilizar esta nueva construcción con MVC que tendrá que obtener la última versión de Ninject a continuación, obtener la versión más reciente de ninject.web.mvc. Construye ninject.web.mvc con la nueva construcción de Ninject.

He estado utilizando esta nueva versión durante aproximadamente una semana con una carga pesada y sin problemas. Ese es el tiempo más largo que ha transcurrido sin ningún problema, por lo que consideraría que se trata de una solución.

+0

¡Impresionante! Esta es una gran noticia. He estado lidiando con eso yo mismo. Gracias por proporcionar esta respuesta, Steve! –

1

Mi respuesta fue un poco más obvia.

He declarado el enlace de uno de mis controladores más de una vez durante la refactorización de mi código.

Cuestiones relacionadas