2011-03-09 6 views
5

Soy nuevo en Ninject, así que estoy seguro de que es algo que estoy haciendo mal, no estoy seguro de qué. Estoy usando Ninject y Ninject.MVC3 en mi aplicación web MVC3. Aquí hay un ejemplo de lo que intento hacer.Ninject no inyectar y lanzar excepciones de referencia nulas

estoy usando el patrón Repositorio:

public interface IRepository<T> 
{ 
    T Get(object id); 
    IList<T> GetAll(); 
    void Add(T value); 
    void Update(T value); 
    void Delete(T value); 
} 

Para un tipo concreto:

public Customer 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Address { get; set; } 

    public Customer() 
    { 
    } 
} 

Ahora tengo 2 repositorios separados, una versión en caché que necesita la inyección en el repositorio de datos:

public CachedCustomerRepository : IRepository<Customer> 
{ 
    private IRepository<Customer> _repository; 

    public Customer Get(object id) 
    { 
     Customer cust = new Customer(); 
     IList<Customer> custs = GetAll(); 
     if (custs != null && custs.Count > 0) 
      cust = custs.FirstOrDefault(c => c.Id == int.Parse(id.ToString())); 

     return cust; 
    } 

    public IList<Customer> GetAll() 
    { 
     IList<Customer> custs = HttpRuntime.Cache["Customers"] as IList<Customer>; 
     if (custs == null) 
     { 
      custs = _repository.GetAll(); 
      if (custs != null && custs.Count() > 0) 
      { 
       double timeout = 600000d; 
       HttpRuntime.Cache.Insert("Customers", custs, null, DateTime.UtcNow.AddMilliseconds(timeout), System.Web.Caching.Cache.NoSlidingExpiration); 
      } 
      else 
      { 
       throw new NullReferenceException(); 
      } 
     } 

     return custs; 
    } 

    public void Add(Customer value) 
    { 
     throw new NotImplementedException(); 
    } 

    public void Update(Customer value) 
    { 
     throw new NotImplementedException(); 
    } 

    public void Delete(Customer value) 
    { 
     throw new NotImplementedException(); 
    } 

    public CachedCustomerRepository() 
    { 
    } 

    [Inject] 
    public CachedCustomerRepository(IRepository<Customer> repository) 
    { 
     _repository = repository; 
    } 
} 

public class CustomerRepository : IRepository<Customer> 
{ 
    public Customer Get(object id) 
    { 
     Customer cust = new Customer(); 
     IList<Customer> custs = GetAll(); 
     if (custs != null && custs.Count > 0) 
      cust = custs.FirstOrDefault(c => c.Id == int.Parse(id.ToString())); 

     return cust; 
    } 

    public IList<Customer> GetAll() 
    { 
     //Customer retrieval code 
    } 

    public void Add(Customer value) 
    { 
     throw new NotImplementedException(); 
    } 

    public void Update(Customer value) 
    { 
     throw new NotImplementedException(); 
    } 

    public void Delete(Customer value) 
    { 
     throw new NotImplementedException(); 
    } 

    public CachedCustomerRepository() 
    { 
    } 
} 

Configuré un NinjectModule como este:

public class ServiceModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IRepository<Customer>>().To<CustomerRepository>(); 
    } 
} 

y he modificado los NinjectMVC3.cs en la carpeta AppStart para obtener el módulo de la hora de crear el kernel:

private static IKernel CreateKernel() 
{ 
    var kernel = new StandardKernel(new ServiceModule()); 
    RegisterServices(kernel); 
    return kernel; 
} 

En mi controlador estoy usando esto:

public ViewResult Index() 
{ 
    IRepository<Customer> custRepo = new CachedCustomerRepository(); 
    return View(custRepo.GetAll()); 
} 

sopla en la línea _repository.GetAll() en mi CachedCustomerRepository.

He establecido un punto de interrupción para asegurarme de que el CreateKernel() se está ejecutando y obteniendo los enlaces, que es. No estoy seguro de por qué la inyección no está sucediendo. Otra nota al margen, no sé si es importante o no, el IRepository, los repositorios y el tipo concreto se encuentran en una biblioteca de clases separada y se mencionan en la aplicación web mvc3. Tanto la aplicación web como la biblioteca de clase tienen una referencia a Ninject y la aplicación web también tiene una referencia a Ninject.MVC3. La creación del enlace y del kernel está teniendo lugar en la aplicación web.

+2

+1 por la frustración que todos experimentan al aprender a utilizar la inyección de dependencia. – TheCloudlessSky

Respuesta

3

Primero, está llamando al constructor incorrecto en su controlador. Este constructor sin parámetros no llama a nada más y es por eso que está obteniendo la excepción nula. Segundo, quiere refactorizar su controlador para que no haya dependencias directas.

te gustaría hacer algo como lo siguiente:

public class SomeController 
{ 
    private readonly IRepository<Customer> repo; 

    public SomeController(IRepository<Customer> repo) 
    { 
     this.repo = repo; 
    } 

    public ViewResult Index() 
    { 
     return View(this.repo.GetAll()); 
    } 
} 

De esta manera, se resuelve el Ninject dependencia para usted! Se le pedirá al kernel de Ninject que cree un controlador con IRepository<Customer> por MVC. Como Ninject tiene este "enlace", intentará crear una instancia del CustomerRepository por usted.

Además, ¿por qué está creando un "CachedRepository"? Realmente, realmente creo que estás optimizando prematuramente esto. Honestamente, solo necesitas el CustomerRepository y lo conectarías dentro del módulo Ninject.

+0

Lo que terminé haciendo fue crear una propiedad para el repositorio e inyectar eso ya que tendré más de un tipo de repo en el controlador en el futuro y también le aplique un atributo personalizado. Esto me permitió usar el enlace de propiedad contextual. –

+1

@Alexander: aunque la inyección de propiedades ciertamente es posible, generalmente es desaprobadora. Para agregar más dependencias de repositorio, simplemente agrega otro argumento de constructor. ¿Qué tipo de enlace contextual necesitas en el controlador? A pesar de eso, me alegra que hayas podido solucionar tu problema. ¡Aclamaciones! – TheCloudlessSky

+0

También es bueno saberlo, no me había dado cuenta de que la inyección de propiedad estaba mal vista. –

0

¿Has hecho que la clase en Global.asax herede NinjectHttpApplication?

+0

Pensé que con Ninject.MVC3 2.2.1.0 no tenías que hacer eso si estás usando el AppStart \ NinjectMVC3.cs –

+0

@Alexander Kahoun: Muy posible; Parece que ha pasado demasiado tiempo desde la última vez que usé Ninject ... –

+0

@Alexander - Estás en lo correcto. Ver mi publicación para más detalles. – TheCloudlessSky

0

Asegúrese de llamar al DependencyResolver.SetResolver(CreateKernel()); para decirle a MVC qué resolver va a utilizar. Puede que lo llames pero no lo vi en tu publicación; de lo contrario, tu código se ve bien.

+0

El uso del código NinjectMVC3.cs lo hace automáticamente. – TheCloudlessSky

+0

Sí, pensé que sí después de publicar mi respuesta. Todavía no he probado las nuevas cosas de AppStart Nuget. Gracias por el definitivo aunque ahora lo sabré en el futuro :) – Buildstarted

+0

Sin preocupaciones :) Lo nuevo hace que la integración con MVC sea realmente fluida. – TheCloudlessSky

0

Para obtener el beneficio completo de usar un IOC, debe refactorizar la dependencia de CachedCustomerRepository desde su clase de controlador. Deberá agregar un nuevo enlace al módulo de su Ninject. Este enlace necesitará usar el contexto para determinar si está vinculando el 'IRepository' con una instancia de CachedCustomerRepository o con la instancia de MVC Controller. Una vez que tenga esto en cuenta, Ninject creará y administrará las vidas de ambos objetos.

0

El problema es que cuando crea el CachedCustomerRepository en su método de acción, solo está instanciando usted mismo y no está obteniendo Ninject instanciarlo para luego inyectar sus dependencias.

Lo que debe hacer es usar la inyección de constructor para el controlador.

E.g.

public class MyController : Controller 
{ 
    public IRepository<Customer> CustomerRepo { get; protected set; } 

    public MyController(IRepository<Customer> customerRepo) 
    { 
     CustomerRepo = customerRepo; 
    } 

    public ViewResult Index() 
    { 
     return View(CustomerRepo.GetAll()); 
    } 
} 

Su escenario es un poco confuso sin embargo, porque se inyecta un IRepository<Customer> en un IRepository<Customer> que necesita ser inyectado en MyController.

Cuestiones relacionadas