2009-10-30 10 views
6

Para empezar estoy usando Ninject 1.5. Tengo dos proyectos: proyecto web y una biblioteca de clase. Mi configuración DI está dentro del proyecto web. Dentro de mi biblioteca de clases tengo el siguiente define:Ninject: ¿Cómo puedo inyectar en una biblioteca de clases?

public interface ICacheService<T> 
    { 
      string Identifier { get; } 
      T Get(); 
      void Set(T objectToCache, TimeSpan timeSpan); 
      bool Exists(); 
    } 

Y entonces una clase concreta llamado CategoryCacheService.

En mi proyecto web que se unen los dos:

Bind(typeof(ICacheService<List<Category>>)).To(typeof(CategoryCacheService)).Using<SingletonBehavior>(); 

En mi biblioteca de clases que tengo métodos de extensión para la clase HtmlHelper, por ejemplo:

public static class Category 
{ 
    [Inject] 
    public static ICacheService<List<Category>> Categories { get; set; } 

    public static string RenderCategories(this HtmlHelper htmlHelper) 
    { 
    var c = Categories.Get(); 

    return string.Join(", ", c.Select(s => s.Name).ToArray()); 
    } 
} 

Me han dicho que usted no puedo inyectar en propiedades estáticas, en su lugar debería usar Kernel.Get <>() - Sin embargo ... Como el código anterior está en una biblioteca de clases, no tengo acceso al Kernel. ¿Cómo puedo obtener el Kernel a partir de este punto o hay una mejor manera de hacerlo?

Respuesta

8

Buena pregunta para preguntar.

La mitad de la idea de utilizar DI es eliminar la preocupación/ajuste del comportamiento de instancias del código bajo inyección. Por lo tanto, puede tener más sentido cambiar la clase Category para que deje de ser static, declare sus dependencias en un ctor y permita que el código del cliente lo una.

En cuanto a cómo acceder a ella si realmente está seguro de que es una buena idea ... En general, la idea en su caso sería crear un CacheServiceResolver y registrarlo [en su proyecto web]. A continuación, páselo como la instancia Kernel que se está construyendo. De esta manera, su DLL solo está vinculada a la interfaz de su CacheServiceResolver.

El otro enfoque que se utiliza a menudo es tener una instalación de "Servicio Localizador" de último recurso en algún lugar global, que expone un "GlobalGet". Pero, en general, es una mala idea y solo debe usarse para propósitos temporales de Taping Duct.

La otra cosa a tener en cuenta es el localizador de servicios comunes, que permitirá a una biblioteca hacer una biblioteca neutral al contenedor, aunque fuera de EL, no encontrará mucho uso como you shouldnt really show your container.

La otra opción es exigir un método de fábrica Func<T> y Bind que a una lambda que lo resuelve, extrayendo esa búsqueda de su código.

EDIT: En Ninject 2, no hay necesidad de pasar de forma explícita en Kernel casos como he dicho - uno puede simplemente pedir una IKernel en su ctor y lo tendrá, sin importar si la solicitud de resolución pasa expclicitly uno en.

EDIT 2: Realmente descontento con mi respuesta, he tratado de hacerlo más general sin que se descuide demasiado.Resumen es que las opciones deseables son generalmente en el siguiente orden:

  1. ningún artefacto de contenedores, deje la costura de cliente
  2. proporciona un neutro punto de extensión recipiente, adaptado para llevar a cabo específicamente algo en el contexto de la biblioteca con terminología en el lenguaje ubicuo de dominio de su biblioteca en lugar de términos abstractos contenedores neutralizados
  3. proporcionan una integración contenedor neutro acercarse a un Servicio de localización Común la
  4. sólo entonces considerar la posibilidad de las personas que necesitan
    • saben su contenedor
    • entienden su contenedor
+0

Ruben, el CacheServiceResolver parece ser la idea correcta para mí desde Puedo volver a usar ese patrón en el futuro. ¿Tiene algún ejemplo sobre la configuración de un resolver? – DennyFerra

+0

Lamentablemente no tengo uno a mano. La idea general sería que, donde sea que esté creando su nuevo StandardKernel, oculte una referencia a él. Luego tiene algo tan simple como 'void RegisterCacheServiceResolver (Kernel kernel) {Bind (). ToConstant (new CacheServiceResolver (kernel));}' en uno de los módulos, a los que pasa el kernel. O podría crear el Kernel, y luego pasarlo al constructor de cualquier Módulo que lo necesite, después de lo cual usted agregará el Módulo [en lugar de pasarlos todos al constructor de Kernel como normalmente lo hace]. –

4

En el proyecto web ejecute el siguiente comando desde la consola de Administrador de paquetes.

Install-Package Ninject.MVC3 

Debería terminar con un módulo NinjectWebCommon en la carpeta App_Start.

Hacia la parte inferior se puede añadir sus dependencias, como a continuación:

private static void RegisterServices(IKernel kernel) 
{ 
kernel.Bind<IPeopleRepository>().To<PeopleRepository>(); 
} 

Desde su proyecto de biblioteca de clases ejecute el siguiente comando:

Install-Package Ninject 

Esto es cómo inyectar un servicio con un repositorio de la biblioteca de clases:

public class PeopleService : IPeopleService 
{ 
private readonly IPeopleRepository _peopleRepository; 

[Inject] 
public PeopleService(IPeopleRepository peopleRepository) 
{ 
    this._peopleRepository = peopleRepository; 
} 
} 
Cuestiones relacionadas