2009-05-22 13 views
6

Supponiamo che disponga dell'interfaccia IRepository e del relativo SqlRepository di implementazione che accetta come argomento LINQ to SQL DataContext. Supponiamo inoltre di disporre dell'interfaccia IService e dei relativi servizi di implementazione che richiedono tre IRepository, IRepository e IRepository. Codice Demo è qui sotto:Iniettare la stessa istanza di DataContext su diversi tipi con Unity

public interface IRepository<T> { } 

public class SqlRepository<T> : IRepository<T> 
{ 
    public SqlRepository(DataContext dc) { ... } 
} 

public interface IService<T> { } 

public class Service<T,T1,T2,T3> : IService<T> 
{ 
    public Service(IRepository<T1> r1, IRepository<T2>, IRepository<T3>) { ... } 
} 

È alcun modo durante la creazione di classe di servizio per iniettare tutti e tre i depositi con la stessa DataContext?

+0

aggiornato la mia risposta –

risposta

7

Tutto quello che dovete fare è assicurarsi che quando si registra il Datacontext con il contenitore di unità utilizzare il PerResolveLifetimeManager sia in config:

<type type="<namespace>.DataContext, <assembly>"> 
    <lifetime type="Microsoft.Practices.Unity.PerResolveLifetimeManager, Microsoft.Practices.Unity" /> 
</type> 

o nel codice:

container.RegisterType<DataContext>(new PerResolveLifetimeManager()); 

allora ogni volta che il contenitore risolve il Service tutte le dipendenze che richiedono anche un DataContext verrà fornito con esattamente lo stesso. Ma la prossima richiesta di risoluzione Service creerà un nuovo DataContext.

0

Se ho capito bene la tua domanda (e se si utilizza l'unità ... suppongo che fate perché avete taggged con unità) si potrebbe fare qualcosa di simile:

Nei tuoi implementions repository,

[InjectionConstructor] 
public SqlRepository(
    [Dependency] DataContext ctx) 

ma è necessario contrassegnare il contructor di servizio nello stesso modo e utilizzare il contenitore per risolvere i servizi e il repository. Anche DataContext deve essere nel contenitore per farlo funzionare.

Un approccio alternativo è quello di fare qualcosa di simile con il repository:

[InjectionMethod] 
public void Initialize(
    [Dependency] DataContext ctx 

questo vi dirà l'unità di chiamare questo metodo se si vuole, nel costruttore servizio, utilizzare l'unità con il metodo accumulo di ... qualcosa di simile:

unitycontainer.BuildUp<IRepository>(repository); 

Credo thats non proprio quello che cercate, ma la prego di dirmi se sto sulla strada giusta e I'll vedere se posso aiutare ulteriormente ...

Cheers/J

+0

Grazie per una prova, ma in realtà, quello che sto cercando di realizzare, è quello di utilizzare la stessa istanza di DataContext durante l'inizializzazione della classe di servizio. Questo è necessario per supportare le transazioni per Repository1, Repository2 e Repository3. ContainertLifeTime non funziona nel mio caso, perché voglio avere un nuovo DataContext per ogni nuova istanza del servizio. – Sergejus

+1

In realtà, penso che il suo approccio sia simile al mio # 2 sopra. Sta iniettando il metodo Initialize e creando il container lì, quindi lo ha eliminato dopo la chiamata. Qualcosa del genere: -> precall. inizializza Contenitore Unity, utilizzando ContainerControlledLifetimeManager in modo che siano singleton. -> Service Initialize call: risolve datacontext, sarà sempre lo stesso datacontext purché il contenitore creato nel precall sia incluso nell'ambito. -> Posta: Smaltire il contenitore ... –

0

Hai provato a utilizzare il metodo RegisterInstance() per il contenitore di unità? Qualcosa del genere potrebbe funzionare:

statico pubblico UnityContainer CreateContainer() { UnityContainer container = new UnityContainer();

 try 
     { 
      var section = ConfigurationManager.GetSection("unity") as UnityConfigurationSection; 

      if (section != null) 
      { 
       section.Containers[0].Configure(container); 
      } 
     } 
     catch (Exception ex) 
     { 
      TraceLogger.LogMessage("Configurarion Error for Unity Container", ex.Message, TraceEventType.Critical); 
      Environment.Exit(1); 
     } 


     container.RegisterInstance(new DataContext()); 
     return container; 
    } 

Ora, ogni volta che il contenitore cerca di costruire un oggetto che ha bisogno di un DataContext, verrà passato la stessa istanza. Potresti anche configurare DataContext prima di registrare la sua istanza.

AGGIORNAMENTO: Un'opzione (ora, non so se è davvero una buona pratica, ma questo ha funzionato per me) è creare un contenitore diverso per ogni oggetto che creerai. Qualcosa di simile:

UnityContainer container1 = ContainerFactory.CreateContainer(); 
UnityContainer container2 = ContainerFactory.CreateContainer(); 
UnityContainer container3 = ContainerFactory.CreateContainer(); 
MyObject1 object1 = container1.Resolve<MyObject1>(); 
MyObject2 object2 = container2.Resolve<MyObject2>(); 
MyObject3 object3 = container3.Resolve<MyObject3>(); 

o un modo più riassunte:

MyObject1 object1 = ContainerFactory.CreateContainer().Resolve<MyObject1>(); 
MyObject1 object2 = ContainerFactory.CreateContainer().Resolve<MyObject2>(); 
MyObject1 object3 = ContainerFactory.CreateContainer().Resolve<MyObject3>(); 

Beh, ci sono un sacco di modi per farlo, creando una lista, utilizzando il modello di fabbrica. Spero che aiuti

+0

Grazie per il suggerimento. Purtroppo ho bisogno dello stesso contesto di dati solo durante la creazione di un singolo oggetto con i vari argomenti di DataContext. Per ogni nuova classe di servizio ho bisogno di un nuovo DataContext. – Sergejus

3

Penso di sapere cosa vuoi fare. Sono nella stessa barca e sto cercando di trovare una soluzione.

Il mio livello di servizio esegue le operazioni nelle richieste in arrivo e ciò che fa dipende dal contenuto. Lo passa a una serie di classi di responsabilità.Voglio che lo stesso contesto venga passato a tutte le classi entro la durata del metodo di servizio chiamato

È possibile specificare PerResolveLifetimeManager. Finora, sembra di poter lavorare con i miei casi di test:

Classe di servizio:

public interface IServiceClass 
{ 
    void DoService(); 
} 

class ServiceClass : IServiceClass 
{ 
    private IHandler Handler { get; set; } 

    public ServiceClass(IHandler handler) 
    { 
     Handler = handler; 
    } 

    public void DoService() 
    { 
     Handler.HandleRequest(); 
    } 
} 

IHandler è realizzato da due classi, ed esegue Catena di modello Responsabilità:

public interface IHandler 
{ 
    void HandleRequest(); 
} 

class Handler : IHandler 
{ 
    private IDataContext DataContext { get; set; } 
    public Handler(IDataContext dataContext) 
    { 
     DataContext = dataContext; 
    } 

    public void HandleRequest() 
    { 
     DataContext.Save("From Handler 1"); 
    } 
} 

class Handler2 : IHandler 
{ 
    private IDataContext DataContext { get; set; } 
    private IHandler NextHandler { get; set; } 

    public Handler2(IDataContext dataContext, IHandler handler) 
    { 
     DataContext = dataContext; 
     NextHandler = handler; 
    } 

    public void HandleRequest() 
    { 
     if (NextHandler != null) 
      NextHandler.HandleRequest(); 

     DataContext.Save("From Handler 2"); 
    } 
} 

Come si può vedere, entrambi i gestori accettano un'istanza di IDataContext, che voglio essere uguale in entrambi. Handler2 accetta anche un'istanza di IHandler per passare il controllo a (lo fa qui per dimostrare, ma in realtà, solo uno gestirà la richiesta ...)

IDataContext. Nel costruttore ho inizializzare un Guid, e durante il suo funzionamento, l'uscita è così posso vedere se entrambe le volte la sua chiamata sta utilizzando la stessa istanza:

public interface IDataContext 
{ 
    void Save(string fromHandler); 
} 

class DataContext : IDataContext 
{ 
    private readonly Guid _guid; 

    public DataContext() 
    { 
     _guid = Guid.NewGuid(); 
    } 

    public void Save(string fromHandler) 
    { 
     Console.Out.WriteLine("GUI: [{0}] {1}", _guid, fromHandler); 
    } 
} 

Infine, la registrazione e la chiamata di servizio:

private IUnityContainer container; 
    private void InitializeUnity() 
    { 
     container = new UnityContainer(); 
     container.RegisterType<IHandler, Handler2>("Handler2", 
      new InjectionConstructor(new ResolvedParameter<IDataContext>(), new ResolvedParameter<IHandler>("Handler1"))); 
     container.RegisterType<IHandler, Handler>("Handler1"); 
     container.RegisterType<IDataContext, DataContext>(new PerResolveLifetimeManager()); 
     container.RegisterType<IServiceClass, ServiceClass>("MyClass", new InjectionConstructor(new ResolvedParameter<IHandler>("Handler2"))); 
    } 

    private void CallService() 
    { 
     var service = container.Resolve<ServiceClass>("MyClass"); 
     service.DoService(); 

     // Resolving and calling again to simulate multiple resolves: 
     service = container.Resolve<ServiceClass>("MyClass"); 
     service.DoService(); 
    } 

questa è l'uscita ottengo:

GUI: [f2250055-8a5f-4f80-a1b6-bcc5574138cf] From Handler 1 
GUI: [f2250055-8a5f-4f80-a1b6-bcc5574138cf] From Handler 2 
GUI: [22a5c0a3-3c5c-4683-807d-bf2b43f3cd0a] From Handler 1 
GUI: [22a5c0a3-3c5c-4683-807d-bf2b43f3cd0a] From Handler 2 

Spero che questo muro di testo risposto alla tua domanda ... Se non mi dispiace, ha ispirato una soluzione avevo bisogno di implementare ...

Problemi correlati