I have a query handler like this:
public class FooQueryHandler : IQueryHandler<FooQuery, FooResult>
{
public FooResult Handle(FooQuery query) {
// Query handled here.
}
}
The IQueryHandler
interface is defined as:
public interface IQueryHandler<TQuery, Result> : where TQuery : IQuery
{
TResult Handle(TQuery query);
}
FooQuery
is defined as:
public class FooQuery : IAuthorizedQuery
where IAuthorizedQuery
is defined as:
public interface IAuthorizedQuery : IQuery
IQuery
is just simple interface. FooResult
is just a simple DTO object.
The IQueryHandler
is injected using Simple Injector and is registered with the container as:
container.Register(typeof(IQueryHandler<,>), assemblies);
The Problem
I want to decorate the IQueryHandler
with a decorator handler class. This decorator should be applied conditionally only if the query object (e.g. FooQuery
) implements IAuthorizedQuery
. This is so some role-based authorization can occur.
If the query does not implement IAuthorizedQuery
and only IQuery
then no decoration should take place.
The handler will need to look like:
public AuthorizationQueryDecorator : IQueryHandler<TQuery, TResult>
where TQuery : IAuthorizedQuery
{
public AuthorizationQueryDecorator(
IQueryHandler<TQuery, TResult> handler,
IAuthorizer<TQuery> authorizer)
{
_authorizer = authorizer;
_handler = handler;
}
private readonly IAuthorizer<TQuery> _authorizer;
private readonly IQueryHandler<TQuery, TResult> handler;
public TResult Handle(TQuery query) {
if(!_authorizer.Authorise(query)) {
// throw exception
}
else {
handler.Handle(query);
}
}
}
The IAuthorizer<TQuery>
interface is just a simple interface with a boolean method Authorise(TQuery query)
that returns true if the query can be executed based on some role-based logic.
The problem is I'm not sure how to register the decorator conditionally with SimpleInjector.
The condition is essentially that an IQueryHandler
should only be decorated if the TQuery object implements IAuthorizationQuery.
How can I do this?
At the moment I have
container.RegisterDecorator(
typeof(IQueryHandler<,>),
typeof(AuthorizationQueryDecorator<,>), \\\ PREDICATE?);
but I don't know what Predicate should be specified?
EDIT
It looks as though the issue I'm having is with the IAuthorizer
registration.
I have the following IAuthorizer
implementations:
public FooQueryAuthorizer() : IAuthorizer<FooQuery>
and
public NullQueryAuthorizer<TQuery, TResult> : IQueryAuthorizer<TQuery, TResult>
where TQuery : IAuthorizedQuery<TResult> : IAuthorizer
The SimpleInjector registration for IQueryAuthorizer
is:
container.RegisterConditional(
typeof(IQueryAuthorizer<,>),
typeof(NullQueryAuthorizer<,>),
c => !c.Handled);
However, the NullQueryAuthorizer
is always used, regardless of whether a specific implementation (e.g. FooQueryAuthorizer
) is present.
How can I get round this?
You don't have to do anything; Simple Injector will automatically apply generic type constraints for you. So your registration is simply this:
container.RegisterDecorator(
typeof(IQueryHandler<,>),
typeof(AuthorizationQueryDecorator<,>));
The documentation describes:
Simple Injector will automatically apply the registered type conditionally based on it generic type constraints