wcf - Castle.Windsor: resolución opcional del componente de una fábrica tipada
dependency-injection castle-windsor (1)
Steven señala dos formas de explorar para llegar a una solución:
- No verifique nulo, más bien use un Patrón de Objeto Nulo
- Envuelva el
IHandler<T>
con un decorador e inyecte el IInjector en el decorador
La segunda opción no era deseable ya que habría cargado a los controladores con una responsabilidad que no tenían que conocer. Idealmente, debería mover este comportamiento de inyección a su propio interceptor independiente y dejarlo vivir completamente allí sin ningún otro código que lo sepa. Puedo hacer eso más tarde.
El primer punto, sin embargo, es el camino a seguir. El Patrón de objeto nulo disminuye la complejidad de mi método y lo deja mucho más claro que con un cheque nulo. Todo lo que tengo que hacer es crear una clase NopInjector
y declararla como el valor predeterminado para la fábrica.
No intente crear un inyector en función de un objeto base:
public class NopInjector : IInjector<object>
{
public void InjectStuff(object target, string stuff) { }
}
Más bien, cree un inyector genérico y regístrelo como un componente genérico abierto
public class NopInjector<T> : IInjector<T>
{
public void InjectStuff(T target, string stuff) { }
}
// registration
_container.Register(
Component.For(typeof(IInjector<>))
.ImplementedBy(typeof(NopInjector<>))
.IsDefault());
_container.Register(
Classes
.FromAssemblyInThisApplication()
.BasedOn(typeof(IInjector<>))
.WithService.AllInterfaces());
Ahora si Castle.Windsor puede resolver un IInjector<Command>
específico IInjector<Command>
lo hará, de lo contrario devolverá el NopInjector
. No más cheque nulo:
private static void DoActualWork<T>(T command)
{
injectorFactory.GetInjector<T>().InjectThings(command, "");
// calling handlers...
}
Tengo una configuración de servicio WCF con Castle.Windsor; los mensajes llegan a un despachador que los envía al componente correcto (básicamente un IHandler<Message>
con un mensaje que es una consulta).
Sin embargo, en algunos casos, hay uno adicional antes de que el controlador pueda actuar; el mensaje debe completarse con datos provenientes de otro lugar. Lo que quiero es verificar si existe un inyector para el tipo de mi mensaje y, si existe uno, ejecútelo.
IInjector<Message> Injector = InjectorFactory.RetrieveInjector<Message>();
if (Injector != null)
{
Logger.InfoFormat("IInjector<{0}> OK", input.GetType().Name);
Injector.InjectCode(input, "Data coming from somewhere else");
}
El razonamiento detrás de esto es que en algún momento futuro alguien puede crear un complemento con un IInjector<Message>
y quiero IInjector<Message>
en el futuro; pero por el momento no existe.
¿Es posible hacer que una fábrica de tipeo devuelva nulo cuando no se encuentra un componente en lugar de lanzar una ComponentNotFoundException
?
EDITAR
Tal como lo discutí con @Steven, responderé mi propia pregunta para recopilar lo que me condujo a la solución y la resolución que encontré. Primero, replanteemos el problema
Tengo un servicio WCF básicamente siguiendo la estructura descrita por Krzysztof Koźmic en este artículo
Sin embargo, antes de llamar a los controladores, quería tener una operación opcional donde el mensaje entrante se modificaría si fuera necesario.
private static void DoActualWork<T>(T command)
{
IInjector<T> Injector = injectorFactory.GetInjector<T>();
if (Injector != null) { Injector.InjectThings(command, ""); }
var handlers = factory.GetHandlersForCommand(command);
foreach (var handler in handlers)
{
handler.Execute();
}
}
Estaba teniendo un problema con injectorFactory; cuando le pedí que encontrara un componente inexistente arrojaría una ComponentNotFoundException
. Lo que me hubiera gustado es que la fábrica reconozca que no hay componentes y simplemente devuelve un valor nulo.