2009-05-22 2 views
6

Angenommen, ich habe IR Repository-Schnittstelle und seine Implementierung SqlRepository, die als Argument LINQ zu SQL DataContext. Angenommen, ich habe die IService-Schnittstelle und ihre Implementierungsdienste, die drei IRepository, IRepository und IRepository benötigen. Demo-Code ist unter:Inject dieselbe DataContext-Instanz über mehrere Typen mit 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>) { ... } 
} 

Ist es eine Möglichkeit, beim Erstellen Service-Klasse alle drei Repositories mit dem gleichen Datacontext zu injizieren?

+0

aktualisiert meine Antwort –

Antwort

7

Alles, was Sie tun müssen, ist sicherzustellen, dass, wenn Sie die Datacontext mit Unity Container registrieren die Verwendung PerResolveLifetimeManager entweder in config:

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

oder in Code:

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

dann, wenn der Behälter löst die Service alle Abhängigkeiten, die auch eine DataContext benötigen werden mit genau der gleichen bereitgestellt werden. Aber die nächste Anfrage zu lösen Service wird eine neue DataContext erstellen.

0

Wenn ich Ihre Frage richtig verstanden habe (und wenn Sie die Einheit verwenden ... Ich nehme an, Sie tun, weil Sie es mit der Einheit taggged haben) Sie so etwas tun könnte:

In Ihrem Repository implementions,

aber dann müssen Sie den Dienstkonstruktor auf die gleiche Weise markieren und den Container verwenden, um Ihre Dienste sowie das Repository aufzulösen. Der DataContext muss auch im Container sein, damit er funktioniert.

Ein alternativer Ansatz ist so etwas wie dies mit Ihrem Repository zu tun:

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

diese Einheit sagen, wird diese Methode aufrufen, wenn Sie, in Ihrem Service-Konstruktor, der Einheit mit der Methode BuildUp verwenden ... so etwas wie dieses:

unitycontainer.BuildUp<IRepository>(repository); 

ich denke, das ist nicht ganz das, was Ihr für suchen, aber bitte sagen Sie mir, wenn ich bin auf dem richtigen Weg und ich werde sehen, ob ich Ihnen weiterhelfen können ...

Prost/J

+0

Danke für einen Versuch, aber tatsächlich, was ich versuche zu erreichen, ist die Verwendung der gleichen DataContext-Instanz während der Service-Klasse-Initialisierung. Dies ist erforderlich, um Transaktionen für das Repository1, das Repository2 und das Repository3 zu unterstützen. ContainertLifeTime funktioniert in meinem Fall nicht, weil ich für jede neue Service-Instanz einen neuen DataContext haben möchte. – Sergejus

+1

Eigentlich denke ich, sein Ansatz ist ähnlich wie bei # 2 oben. Er injiziert die Initialize-Methode und erstellt dort den Container und entsorgt ihn anschließend. Etwas wie dieses: -> precall. initialisieren Unity Container mit ContainerControlledLifetimeManager, so dass sie Singletons sind. -> Service Anruf initialisieren: resolve datacontext, wird immer der gleiche Datenkontext sein, solange der im Precall erstellte Container im Bereich ist. -> Post Call: Entsorgen Sie den Container ... –

0

Haben Sie versucht, die RegisterInstance() - Methode für den Einheitscontainer zu verwenden? So etwas könnte funktionieren:

public static UnityContainer CreateContainer() { UnityContainer container = neu 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; 
    } 

Nun, jedes Mal wenn dieser Container ein Objekt zu bauen versucht, die eine Datacontext muss, wird die gleiche Instanz übergeben werden. Sie können den DataContext sogar vor der Registrierung seiner Instanz konfigurieren.

UPDATE: Eine Option (jetzt weiß ich nicht, ob es wirklich eine gute Praxis ist, aber das funktionierte für mich) ist, einen anderen Container für jedes Objekt zu erstellen. Etwas wie:

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>(); 

oder mehr zusammengefasst Weise:

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

Nun, es gibt viele Möglichkeiten, es zu tun, um eine Liste erstellen, mit den Fabrik-Mustern. Hoffe es hilft

+0

Vielen Dank für den Vorschlag. Leider brauche ich denselben Datenkontext nur beim Erstellen eines einzelnen Objekts mit den verschiedenen DataContext-Argumenten. Für jede neue Dienstklasse benötige ich neuen DataContext. – Sergejus

3

Ich denke, ich weiß, was Sie tun möchten. Ich bin im selben Boot und versuche, eine Lösung zu finden.

Meine Service-Schicht führt Operationen bei kommenden Anforderungen aus, und was es tut, hängt vom Inhalt ab. Es übergibt es an eine Kette von Verantwortungsklassen.Ich möchte, dass derselbe Kontext an alle Klassen innerhalb der Lebensdauer der Servicemethode

weitergegeben wird. Sie können PerResolveLifetimeManager angeben. Bisher scheint es mit meinem Testfälle zu arbeiten:

Service-Klasse:

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 von zwei Klassen implementiert wird, und führt eine Zuständigkeitskette Muster:

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"); 
    } 
} 

Wie Sie kann sehen, beide Handler akzeptieren eine Instanz von IDataContext, die in beiden gleich sein soll. Handler2 akzeptiert auch eine Instanz von IHandler, an die die Kontrolle übergeben werden soll (beide demonstrieren hier, aber tatsächlich würde nur einer die Anfrage bearbeiten ...)

IDataContext. Im Konstruktor initialisieren ich ein Guid, und während des Betriebs, Ausgabe, die es so kann ich, wenn beide mal sehen seine unter Verwendung der gleichen Instanz genannt:

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); 
    } 
} 

Schließlich Registrierung und Berufung Service:

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(); 
    } 

Dies ist die Ausgabe erhalte ich:

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 

Hoffnung diese Wand von Text Ihre Frage beantwortet ... Wenn nicht traurig, es eine Lösung inspirieren habe ich umsetzen musste ...

Verwandte Themen