34

Estoy en proceso de crear un proveedor de membresía personalizado para un sitio web ASP.Net MVC. El proveedor se está creando como una clase separada como parte de una biblioteca más grande. Existe la necesidad de que el almacén de datos de fondo sea flexible, ya que podría ser un archivo Xml o una base de datos SQL. Mi idea inicial fue crear una interfaz para el almacén de datos e inyectar esto en el proveedor usando la inyección de dependencia.Inyección de dependencia y proveedores de membresía ASP.Net

El resultado final es que un desarrollador puede heredar la interfaz del almacén de datos y proporcionar los métodos necesarios para actualizar los datos, que luego serán utilizados por los proveedores de membresía personalizados.

Sin embargo, debido a mi propia falta de habilidad no puedo encontrar la manera de inyectar la clase en el proveedor de membresía cuando la agrego al sitio web. ¿Qué se necesita hacer para vincular el almacén de datos con el proveedor? ¿Cuál sería la forma más sencilla de habilitar esto en el sitio web?

+0

¿Está familiarizado con los marcos de inyección de dependencia? – Restuta

+0

@Restuta - No. No estoy buscando un marco. Una interfaz simple será suficiente para este requisito específico.Los desarrolladores deberían poder crear sus propias tiendas de back-end simplemente heredando la interfaz. – BinaryMisfit

+1

Creo que el framework puede ahorrarle mucho tiempo. Se usará para inyectar una realización específica en su proveedor de Membresía personalizado, esta tarea es la más compleja, ya que no puede controlar la inicialización del proveedor. – Restuta

Respuesta

31

Si está configurando los proveedores de membresía personalizados a través del elemento membership> < en el archivo Web.config, entonces puedo ver los problemas que tendrá con la inyección de dependencia.

Los proveedores son construidos y gestionados por el marco, y no hay oportunidad para que usted intercepte esa construcción para proporcionar inyección de dependencia adicional para la interfaz IDataStore.

Si mi suposición es correcta, entonces lo que puede hacer es anular el método Initialize() en su proveedor personalizado, y realizar allí la inyección de dependencia. Puede tener una configuración personalizada de nombre/valor en la configuración del proveedor que apunte a un tipo que implemente IDataStore, que se pasa como parte de un diccionario al método Initialize().

A continuación, se activa una instancia del tipo de almacén de datos y la puso sobre la propiedad adecuada:

public class MyMembershipProvider : MembershipProvider 
{ 
    public IDataStore DataStore 
    { 
     get; 
     set; 
    } 

    public override Initialize(string name, NameValueCollection config) 
    { 
     var dataStoreType = config["dataStoreProvider"]; 
     if (!String.IsNullOrEmpty(dataStoreType)) 
     { 
      var type = Type.GetType(dataStoreType); 
      DataStore = (IDataStore) Activator.CreateInstance(type); 
     } 
    } 
} 

Initialize() será llamado por el marco después de que se construye una instancia de su proveedor, por lo que es el lugar perfecto para hacer cualquier trabajo de configuración adicional como este.

Para escenarios de prueba, simplemente establece la propiedad del almacén de datos en la instancia del proveedor, ya que la va a construir directamente en sus pruebas.

+1

Perfecto. El código que estaba buscando. ¡Gracias! – BinaryMisfit

+0

Se ha realizado una corrección de forma similar aquí: http://bugsquash.blogspot.com.au/2010/11/windsor-managed-membershipproviders.html Básicamente implementa el Patrón de diseño del decorador para envolver la instancia creada por su Contenedor DI. –

+0

Esto ya no parece funcionar en .Net 4.6.2 – IronSean

2

La forma más simple de hacer la inyección de dependencia que he visto (y en realidad la única que he usado hasta ahora ...) es hacer que un constructor de su clase dependiente tome la interfaz como parámetro y asignar a un campo privado. Si lo desea, también puede agregar un constructor "predeterminado", que encadena al primero con un valor predeterminado.

simplificado, se vería algo como esto:

public class DependentClass 
{ 
    private IDataStore _store; 

    // Use this constructor when you want strict control of the implementation 
    public DependentClass(IDataStore store) 
    { 
     this._store = store; 
    } 

    // Use this constructor when you don't want to create an IDataStore instance 
    // manually every time you create a DependentClass instance 
    public DependentClass() : this(new DefaultDataStore()) { } 
} 

El concepto se llama "Constructor de encadenamiento", y hay una gran cantidad de artículos en la web sobre la manera de hacerlo. Encuentro this tutorial muy explicativo del patrón DI.

+0

Gracias. Uso DI con bastante frecuencia, así que estoy bastante cómodo con esta parte. Mi problema es específico del proveedor de membresía que se configura en el web.config. La solución de Sam resuelve este problema. – BinaryMisfit

+0

@Sleeper: dice que está usando ASP.NET MVC, lo que significa que * es posible * resolver la clase a través de un contenedor. Sugiero que él debería. Y, por cierto, no tienes que gritar. –

20

¿No es esto mejor? Lo uso con MVC3 y ninject. Es suficiente agregar una propiedad a su clase de proveedor de membresía personalizada. Recuerde agregar "using System.Web.Mvc;" en la parte superior.

public IRepository Repository 
{ 
    get 
    { 
     return DependencyResolver.Current.GetService<IRepository>(); 
    } 
} 
+0

Posiblemente. No he mirado esto por un tiempo, y en el momento en que se formuló la pregunta, todavía era MVC 1.0 – BinaryMisfit

+1

Funciona para mí. El inconveniente es que se trata de una variación del patrón de "Localizador de servicios", pero a veces hay que hacer concesiones arquitectónicas. (Consulte http://stackoverflow.com/questions/22795459/is-servicelocator-anti-pattern). No sé si se supone que deben arreglar esto en ASP.NET vNext, pero con suerte. –

Cuestiones relacionadas