2009-12-11 7 views
9

Sto cercando di capire come utilizzare IoC in situazioni in cui le classi dipendenti possono cambiare in base ad alcune variabili nell'applicazione (in questo caso, stato della sessione). Ad esempio, ciascuno dei nostri clienti ha un database diverso, quindi la connessione al database deve essere costruita su un valore archiviato nella loro sessione (in particolare poiché alcuni utenti potrebbero avere più database se possiedono più attività commerciali e passeranno da un database all'altro) .Come configurare IoC quando una classe chiave richiede Session (o altre variabili specifiche del contesto)

Ecco un esempio generico di come avremmo attualmente installato questa struttura:

public class MyTestController : ControllerBase 
{ 
    Repository _rep; 

    public MyTest(Repository rep) 
    { 
     _rep = rep; 
    } 

    public MyTest() 
    { 
     string connString = String.Format("Server={0}; Database={1};" 
      , SessionContainer.ServerName, SessionContainer.DatabaseName; 
     var dc = new DataContext(connString); 
     _rep = new Repository(dc); 
    } 

    public int SampleFn() 
    { 
     return _rep.GetCountOfEmployees(); 
    } 
} 

public class Repository 
{ 
    DataContext _context; 

    public Repository(DataContext context) 
    { 
     _context = context; 
    } 
} 

saremmo in grado di impostare questa funzione utilizzando CIO e eliminare le c-tori di default? Se é cosi, come? Non ho problemi usando solo D.I. in questo modo, ma mi piacerebbe esplorare la possibilità di un StructureMap o Unity (nota: normalmente passiamo in db/server a una classe factory che crea il datacontext ... sopra l'esempio è solo per brevità).

risposta

13

Il modo in cui l'istanza del repository viene creata, così come la sua durata, non è di alcuna importanza per il controller.

Quando si registrano i componenti nel contenitore, è necessario specificare la durata del componente. A seconda dell'implementazione, puoi semplicemente scegliere di impostare il periodo di validità del repository per seguire la sessione.

In ogni caso è possibile utilizzare un factory per creare il repository dalla sessione, ma farlo fuori dal controller.

È assolutamente necessario eliminare il costruttore predefinito.


Fuori della parte superiore della mia testa non riesco a ricordare come fare questo in Unity o StructureMap, ecco un esempio il Castello di Windsor.

Definire un Abstract Factory:

public interface IRepositoryFactory 
{ 
    Repository Create(); 
} 

e un'implementazione

public class MyRepositoryFactory : IRepositoryFactory 
{ 
    private readonly HttpContextBase httpContext; 

    public MyRepositoryFactory(HttpContextBase httpContext) 
    { 
     if (httpContext == null) 
     { 
      throw new ArgumentNullException("httpContext"); 
     } 

     this.httpContext = httpContext; 
    } 

    #region IRepositoryFactory Members 

    public Repository Create() 
    { 
     // return Repository created from this.httpContext 
    } 

    #endregion 
} 

Ora registrare tutte le cose

container.AddFacility<FactorySupportFacility>(); 
container.Register(Component.For<IRepositoryFactory>() 
    .ImplementedBy<MyRepositoryFactory>() 
    .LifeStyle.PerWebRequest); 
container.Register(Component.For<Repository>() 
    .UsingFactory((IRepositoryFactory f) => f.Create()) 
    .LifeStyle.PerWebRequest); 

Qui ho usato lo stile di vita PerWebRequest, ma se si vuoi ottimizzare potresti voler creare uno stile di vita PerWebSession personalizzato. Questo non è troppo difficile da fare a Castle, ma non riesco a ricordare quanto sia difficile in altri contenitori DI.

Sarà inoltre necessario registrare HttpContextBase, poiché MyRepositoryFactory dipende da esso.

+0

Mark: puoi essere più specifico o fornire un esempio? Potremmo avere più oggetti repository, ognuno dei quali avrebbe bisogno di utilizzare lo stesso DataContext (per un'elaborazione della transazione corretta). Non ho problemi a registrarlo nel contenitore IoC quando "DataContext" utilizza una stringa di connessione che è globale o definita nel contenitore, ma per quanto riguarda il momento in cui la stringa di connessione si trova nella sessione dell'utente? Mi sento come se mi mancasse qualcosa di ovvio. –

+0

Aggiunto un esempio alla mia risposta. –

+0

Ah ah, penso di averlo subito! =) Ti ho downvoted in modo da poterti invitare domani per doppia vittoria. Grande risposta. –

Problemi correlati