On command handlers, I want to set transaction handling. I don't want to set transactions on all methods because it has performance leaks. In essence, I want to set this attribute to check if the transaction should be set or not. Currently, I am able to access the request attribute, but I want access to the handler attribute.
The [SqlTransactionAttribute] is just a simple marker attribute
[SqlTransactionAttribute]
public class LoginUserCommandHandler : IRequestHandler<LoginUserCommand, TokenDTO>
{
//Command handler implementation
}
The problem now is that in the pipeline behavior how to determine whether a handler has SqlTransactionAttribute or not
public class TransactionBehavior<TRequest, TResponse> :
IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
where TResponse : notnull
{
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
//how to get command handler
if (Attribute.GetCustomAttribute(typeof(handler), typeof(SqlTransactionAttribute)) != null)
{
await HandleSqlTransaction(next);
}
}
}
Adding this attribute to the command allows me to read it(from TRequest), however, I'd prefer to read it from the handler as the logic must be in the handler and it will be more readable.
Inject the RequestHandler into the constructor.
public class TransactionBehavior<TRequest, TResponse> :
IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
where TResponse : notnull
{
private readonly IRequestHandler<TRequest, TResponse> requestHandler;
public TransactionBehavior(IRequestHandler<TRequest, TResponse> requestHandler)
{
this.requestHandler = requestHandler;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var hasSqlTransactionAttribute = requestHandler.GetType().GetCustomAttributes<SqlTransactionAttribute>().Any();
if (hasSqlTransactionAttribute)
{
await HandleSqlTransaction(next);
}
}
}