c# - Unity DI en un servicio de Windows, ¿es posible?
dependency-injection windows-services (1)
Estoy desarrollando un servicio de Windows para realizar algunas operaciones periódicas, ¿puedo usar Unity para inyectar mis clases desde otra biblioteca allí?
Deseo usar el atributo [Dependencia] en mis servicios, registrando los componentes en el punto de entrada del inicio del servicio de Windows.
Ejemplo:
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
UnityConfig.RegisterComponents();
ServicesToRun = new ServiceBase[]
{
new EventChecker()
};
ServiceBase.Run(ServicesToRun);
}
}
public static class UnityConfig
{
public static void RegisterComponents()
{
UnityContainer container = new UnityContainer();
container.RegisterType<IEventBL, EventBL>();
}
}
public partial class EventChecker : ServiceBase
{
private Logger LOG = LogManager.GetCurrentClassLogger();
[Dependency]
public Lazy<IEventBL> EventBL { get; set; }
protected override void OnStart(string[] args)
{
var events = EventBL.Value.PendingExecution(1);
}
}
En este escenario, EventBL siempre es nulo, por lo que no se resuelve con la [Dependencia] de la unidad. No hay una manera de hacerlo funcionar?
¡Gracias!
Solución encontrada:
Después de escribir la respuesta, encontré una posible solución, llamándome para crear el método del contenedor para crear las obras de la clase de servicio:
UnityContainer container = new UnityContainer();
UnityConfig.RegisterComponents(container);
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
container.BuildUp(new EventChecker())
};
ServiceBase.Run(ServicesToRun);
Si conoce alguna otra solución, por favor, comparta :)
Por supuesto, puede usar una biblioteca DI para ayudarlo con los Servicios de Windows. Tenga en cuenta que, en general, debería preferir usar la inyección de constructor. Esto evita el acoplamiento temporal y evita que su código dependa de la biblioteca DI (lo cual es bastante irónico de tener que depender de la biblioteca DI, ya que está tratando de ayudarlo a evitar un fuerte acoplamiento entre los componentes).
Además, simplemente debe dejar que el contenedor resuelva sus servicios. En otras palabras, no actualice sus servicios a mano, pero solicite una nueva instancia del contenedor:
ServicesToRun = new ServiceBase[]
{
container.Resolve<EventChecker>()
};
Pero tenga en cuenta que su EventChecker
se resuelve una vez y se almacena durante la aplicación. Eso efectivamente lo convierte en un singleton y con eso todas sus dependencias se convertirán en singletons. Por lo tanto, en su lugar, es mejor hacer que la implementación de ServiceBase
parte de la raíz de la composición y resolver las nuevas instancias desde el contenedor cada vez que se dispare su tiempo:
public class EventChecker : ServiceBase
{
private static IUnityContainer container;
public EventChecker(IUnityContainer container) {
this.container = container;
}
public void SomeOperationThatGetsTriggeredByATimer() {
using (this.container.StartSomeScope()) {
var service = this.container.Resolve<IEventCheckerService>();
service.Process();
}
}
}