2009-05-22 9 views
6

Supongamos que tengo una interfaz IRepository y su implementación SqlRepository que toma como argumento LINQ to SQL DataContext. Supongamos también que tengo la interfaz IService y sus servicios de implementación que toman tres IRepository, IRepository y IRepository. código de demostración es el siguiente:Inyectar la misma instancia DataContext en varios tipos 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>) { ... } 
} 

No es de forma, mientras que la creación de la clase de servicio para inyectar los tres repositorios con el mismo DataContext?

+0

actualicé mi respuesta –

Respuesta

7

Todo lo que necesita hacer es asegurarse de que cuando se registra la Datacontext con su contenedor de la unidad utilizan el PerResolveLifetimeManager ya sea en config:

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

o en el código:

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

entonces siempre que el envase resuelve el Service las dependencias que también requieren un DataContext se proporcionará exactamente el mismo. Pero la siguiente solicitud para resolver Service creará un nuevo DataContext.

0

Si entiendo bien su pregunta (y si está utilizando la unidad ... supongo que haces porque has taggged con la unidad) se podría hacer algo como esto:

En sus implementions repositorio,

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

pero luego debe marcar el constructor del servicio de la misma manera y usar el contenedor para resolver sus servicios y el repositorio. El DataContext también debe estar en el contenedor para que funcione.

Un enfoque alternativo es hacer algo como esto con su repositorio:

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

esto le dirá la unidad llamar a este método si se quiere, en su constructor servicio, utilice la unidad con el método de acumulación ... algo como esto:

unitycontainer.BuildUp<IRepository>(repository); 

supongo que eso no es todo lo que tu buscas, pero por favor dime si estoy en el camino correcto y voy a ver si puedo ayudarle más ...

Cheers/J

+0

Gracias por intentarlo, pero en realidad, lo que intento lograr es utilizar la misma instancia de DataContext durante la inicialización de la clase de servicio. Esto es necesario para admitir transacciones para Repository1, Repository2 y Repository3. ContainertLifeTime no funciona en mi caso, porque quiero tener un nuevo DataContext para cada nueva instancia de servicio. – Sergejus

+1

En realidad, creo que su enfoque es similar a mi # 2 anterior. Está inyectando el método Initialize y creando el contenedor allí, luego desechando la llamada posterior. Algo como esto: -> precall. inicializa Unity Container, usando ContainerControlledLifetimeManager para que sean singletons. -> Llamada de inicialización del servicio: resolver el contexto de datos, siempre será el mismo contexto de datos siempre que el contenedor creado en la prellamada esté dentro del alcance. -> Llamada de correos: Deseche el contenedor ... –

0

¿Ha intentado utilizar el método RegisterInstance() para el contenedor de unidad? Algo como esto podría funcionar:

public static 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; 
    } 

Ahora, cada vez que este contenedor trata de construir un objeto que necesita un DataContext, se pasará la misma instancia. Incluso podría configurar DataContext antes de registrar su instancia.

ACTUALIZACIÓN: Una opción (ahora, no sé si es realmente una buena práctica, pero esto funcionó para mí) es crear un contenedor diferente para cada objeto que vas a crear. Algo así como:

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 una manera más resumida:

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

Bueno, hay un montón de maneras de hacerlo, la creación de una lista, utilizando el patrón de la fábrica. Espero que ayude

+0

Gracias por la sugerencia. Desafortunadamente, necesito el mismo contexto de datos solo cuando creo un solo objeto con varios argumentos de DataContext. Para cada nueva clase de servicio, necesito un nuevo DataContext. – Sergejus

3

Creo que sé lo que quieres hacer. Estoy en el mismo barco y estoy tratando de encontrar una solución.

Mi capa de servicio realiza operaciones en las próximas solicitudes, y lo que hace depende de los contenidos. Lo pasa a una serie de clases de cadena de responsabilidad.Quiero que se pase el mismo contexto a todas las clases dentro de la vida útil del método de servicio llamado

Puede especificar PerResolveLifetimeManager. Hasta el momento, parece estar funcionando con mis casos de prueba:

Servicio Clase:

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 se lleva a cabo por dos clases, y lleva a cabo la cadena de patrón de Responsabilidad:

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

Como puede ver, ambos controladores aceptan una instancia de IDataContext, que quiero ser el mismo en ambos. Handler2 también acepta una instancia de IHandler para pasar el control a (aquí hace ambos para demostrar, pero en realidad, solo uno manejaría la solicitud ...)

IDataContext. En el constructor que inicializa un Guid, y durante su funcionamiento, la salida es para que pueda ver si las dos veces su llamada está utilizando la misma instancia:

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

Por último, el registro y la vocación de servicio:

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

ésta es la salida me sale:

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 

esperanza este muro de texto respondió a su pregunta ... Si no lo siento, inspiraba una solución que necesitaba para poner en práctica ...

Cuestiones relacionadas