I am playing around with a test project. I am trying to implement a CQS pattern and I am getting close to wrapping up the initial tests. I have run into an issue with trying to resolve my IQueryValidtor<>
and IQueryHandler<,>
classes. The method resolves them alright, but when i try to access the interface methods implemented in the concrete class, i get
The best overloaded method match for 'MyProjectsNamespace.GetSiteValidator.Validate(MyProjectsNamespace.Queries.GetSite)' has some invalid arguments.
I am basing my code on this answer I found. Everything appears to be lining up during design time, but run time is a different story.
I am including all of the interfaces, implementations, and unit tests that I am working with on this issue. The first unit test is actually working. It is the last two that are actually trying to use the resolved classes. I am using Autofac for my dependency injection.
public interface IQuery<TResult> {
}
public class GetSite : IQuery<Site> {
public Guid Id { get; set; }
}
public interface IValidator<T> {
Task<List<ValidationResult>> Validate(T command);
}
public class GetSiteValidator : IValidator<GetSite> {
public async Task<List<ValidationResult>> Validate(GetSite command) {
List<ValidationResult> results = new List<ValidationResult>();
if(command == null) {
throw new ArgumentNullException(nameof(command));
}
if(command.Id == Guid.Empty) {
results.Add(new ValidationResult() { FieldName = "Id", Message = "Is empty" });
}
return results;
}
}
public interface IQueryHandler<in TQuery, TResult> where TQuery : IQuery<TResult> {
Task<TResult> Handle(TQuery query);
}
public class GetSiteHandler : IQueryHandler<GetSite, Site> {
public Task<Site> Handle(GetSite query) {
throw new NotImplementedException();
}
}
The code above is all of the interfaces and concrete classes used in this problem. The code below is the dispatcher class where i am having the issue.
public class QueryDispatcher : IQueryDispatcher {
private readonly IComponentContext _context;
public QueryDispatcher(IComponentContext context) {
_context = context;
}
public async Task<TResult> Dispatch<TResult>(IQuery<TResult> query) {
if (query == null) {
throw new ArgumentNullException(nameof(query), "Query cannot be null");
}
// use dynamic datatype because the tresult is not known at compile time
var validatorType = typeof(IValidator<>).MakeGenericType(query.GetType());
dynamic validator = _context.Resolve(validatorType);
var handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult));
dynamic handler = _context.Resolve(handlerType);
List<ValidationResult> errors = await validator.Validate(query);
if(errors.Count == 0) {
return await handler.Handle(query);
} else {
// raise failed validation event
throw new ApplicationException("Not implemented");
}
}
}