I have an open generic type AccessMessageHandler<TProcess>
which I want to resolve every time that an IProcessHandler<AccessMessage<TProcess>>
is resolved. How can I do this?
This is my code:
public interface IProcess {}
public interface IProcessHandler<in TProcess> where TProcess : IProcess {
void Handle(TProcess message);
}
public class AccessMessage<TProcess> : IProcess where TProcess : IProcess {
public virtual string Username {get;protected set;}
public virtual TProcess InnerProcess { get; protected set; }
}
public class AccessMessageHandler<TProcess> : IProcessHandler<AccessMessage<TProcess>>
where TProcess : IProcess {
public AccessMessageHandler(IProcessHandler<TProcess> innerHandler){}
public void Handle(AccessMessage<TProcess> message){
// access control
_innerHandler.Handle(message.InnerProcess)
}
}
public class JustDoIt : IProcess {
public virtual string What {get;set;}
}
public class JustDoItHandler : IProcessHandler<JustDoIt> {
public void Handle(JustDoIt message) {
// handle
}
}
How can i register IProcessHandler, AccessMessageHandler for Simple Injector resolve like below:
var accessMessageProcess = new AccessMessage<JustDoIt>()
{
Username = "user",
InnerProcess = new JustDoIt() { What="xxx" }
};
var handler = GetHandlerFor(accessMessageProcess);
// must return AccessMessageHandler<JustDoIt>(JustDoItHandler)
handler.Handle(accessMessageProcess);
You can do the following registration:
container.RegisterManyForOpenGeneric(
typeof(IProcessHandler<>),
typeof(JustDoItHandler).Assembly);
container.RegisterOpenGeneric(
typeof(IProcessHandler<>),
typeof(AccessMessageHandler<>));
The call to RegisterManyForOpenGeneric
will search the assembly of the JustDoItHandler
and looks for all public concrete (non-generic) implementations of IProcessHandler<TProcess>
. In the end this is just the same as doing a bunch of manual calls to container.Register<IProcessHandler<SomeProcess>, SomeProcessHandler>()
.
The call to RegisterOpenGeneric
maps an open generic abstraction to an open generic type. It uses unregistered type resolution on the background, so every time a IProcessHandler<TProcess>
is requested that is not registered explicitly (using RegisterManyForOpenGeneric
for instance), an AccessMessageHandler<TProcess>
is resolved (if the generic type constraints match).
The following code can be used to resolve the object graph and execute the handler:
var handler = container.GetInstance<IProcessHandler<AccessMessage<JustDoIt>>>();
handler.Handle(accessMessageProcess);
This should resolve the following graph:
IProcessHandler<AccessMessage<JustDoIt>> handler =
new AccessMessageHandler<JustDoIt>(
new JustDoItHandler());
Do note though that the AccessMessageHandler<TProcess>
is not a decorator. A decorator wraps the same type as it implements, but your AccessMessageHandler<TProcess>
implements IProcessHandler<AccessMessage<TProcess>>
but wraps IProcessHandler<TProcess>
. I think the right name for this pattern is a proxy.