2009-08-20 10 views
10

Estoy tratando de usar el contenedor Unity para que resulte más fácil probar mis controladores unitarios. Mi controlador usa un constructor que acepta una interfaz para un Repositorio. En el archivo global.asax, instalo un UnityContainerFactory y lo registro con el framework MVC y luego registro el repositorio y su implementación. Agregué el atributo [Dependency] al parámetro del Depósito CTOR del controlador. Todo parece funcionar bien, excepto que ocasionalmente se llama al GetControllerInstance (Type controllerType) de la fábrica más de una vez y se pasa un argumento nulo como el controllerType.ASP.NET MVC y Unity 1.2 Pregunta de contenedor

La primera llamada a la fábrica es siempre correcta y el ControllerType "ProductsController" se transfiere como argumento. Pero a veces, la fábrica se llama un par de veces más después de que la vista se haya mostrado con un valor nulo para el controlador y no estoy seguro de por qué. Cuando se pasa el valor correcto del tipo de controlador, "Call Stack" tiene sentido para mí, pero cuando se pasa un nulo, no estoy seguro de por qué o quién está haciendo la llamada. ¿Algunas ideas?

El código y las pilas de llamadas para el ejemplo se muestran a continuación.

pila de llamadas cuando se trabaja

test.dll! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance (System.Type controllerType = {Nombre = "ProductsController" FullName = "Test.Controllers.ProductsController"}) Línea 23 C# test.dll! Test._Default.Page_Load (object sender = {} ASP.default_aspx, System.EventArgs e = {} System.EventArgs) Línea 18 + 0x1a bytes C#

pila de llamadas cuando se pasa NULL en el controllerType

Test.DLL! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance (Syst em.Type controllerType = null) Línea 27 C#

Primero creé un UnityControllerFactory

public class UnityControllerFactory : DefaultControllerFactory 
{ 
    UnityContainer container; 

    public UnityControllerFactory(UnityContainer container) 
    { 
     this.container = container; 
    } 

    protected override IController GetControllerInstance(Type controllerType) 
    { 
     if (controllerType != null) 
     { 
      return container.Resolve(controllerType) as IController; 
     } 
     else 
     { 
      return null; // I never expect to get here, but I do sometimes, the callstack does not show the caller 
     } 
    } 
} 

A continuación, he añadido el siguiente código en el archivo Global.asax para crear instancias de la fábrica de envases

protected void Application_Start() 
    { 
     RegisterRoutes(RouteTable.Routes); 

     // Create Unity Container if needed 
     if (_container == null) 
     { 
      _container = new UnityContainer(); 
     } 

     // Instantiate a new factory 
     IControllerFactory unityControllerFactory = new UnityControllerFactory(_container); 

     // Register it with the MVC framework 
     ControllerBuilder.Current.SetControllerFactory(unityControllerFactory); 

     // Register the SqlProductRepository 
     _container.RegisterType<IProductsRepository, SqlProductRepository> 
      (new ContainerControlledLifetimeManager()); 
    } 

La aplicación tiene un controlador

public class ProductsController : Controller 
{ 
    public IProductsRepository productsRepository; 

    public ProductsController([Dependency]IProductsRepository productsRepository) 
    { 
     this.productsRepository = productsRepository; 
    } 
} 
+0

¿Está 100% seguro de que esta línea no devuelve nulo: return container.Resolve (controllerType) como IController; Parece poco probable, pero ese molde podría devolver nulo fácilmente si el tipo resultante no era un IController o la llamada Resolver falló. –

+0

Hola Anderson, Como puedes ver en la pila de llamadas, se está pasando nulo. También detuve en la línea usando el depurador y es nulo antes del lanzamiento. Esta llamada es la única función en la pila en ese momento. Lo cual tampoco entiendo. Test.DLL! Test.UnityHelpers.UnityControllerFactory.GetControllerInstance (System.Type controllerType = null) Línea 27 C# – Rick

+0

Eso es lo que pensé que estaba viendo en tu pila, pero quería verificar mis suposiciones para asegurarme. –

Respuesta

9

Esto es probable debido a algún archivo t no está mapeando a un controlador en sus rutas. (imágenes, por ejemplo). Esto sucederá más a menudo cuando esté depurando localmente con Cassini en mi experiencia, ya que Cassini permite que todas las solicitudes se dirijan a través de ASP.NET mientras se encuentra en IIS, IIS maneja muchas de las solicitudes por usted. Esta también sería la razón por la cual no ve su código en la pila para esta solicitud. Si desactivas la opción "Just My Code" en Visual Studio, a veces puedes obtener una mejor pista sobre estas cosas.

Sin embargo, esta no es la única razón por la que esto puede suceder, pero es común.

Lo apropiado sería permitir que el método base maneje la solicitud en estas situaciones. Por lo general, es solo una simple solicitud de archivo y no debería tener ningún impacto en usted.

Lo más sencillo sería la de la puerta de esta manera:

if (controllerType != null) 
    { 
     return container.Resolve(controllerType) as IController; 
    } 
    else 
    { 
     return base.GetControllerInstance(requestContext, controllerType); 
    } 

Eso debería hacerlo.

Para ver para qué sirve la solicitud, es posible que pueda consultar HttpContext.Current.Request para ver qué archivo no está en su ruta. Muchas veces no es algo que controle, pero le hará sentir mejor saber cuál es el origen de la solicitud.

+0

Gracias por la respuesta y los consejos ..... – Rick

+2

Tomé su sugerencia y miré el HttpContext.Current.Request y noté que estaba buscando favicon.ico. Eso explica por qué funcionó a veces y no a otros. Cuando una instancia existente del navegador estaba abierta, no intentó encontrar favicon.ico. – Rick

+0

Hola, es bueno saber y me alegro de poder ayudarte. –