An implementation of a validation query would need to implement a similar interface:
public interface IValidationQuery<oout TDelegate>
{
T Query { get; }
}
Two projects: ValidationQueries.Contracts - which can be used by any projects - it has no dependencies to anything but potentially the Concepts project.
ValidationQueries - the implementation of the contracts. It could have a dependency to the Read side - the Read project
In your ValidationQueries.Contracts project
public namespace ValidationQueries.Contracts
{
// Do not allow for same work being requested for same area
public delegate bool TicketMustBeUniquePerAreaAndWork(Area area, WorkType workType);
}
The implementation of this would then be:
public class TicketMustBeUniquePerAreaAndWork : IValidationQuery<Contracts.TicketMustBeUniquePerAreaAndWork>
{
public Contracts.TicketMustBeUniquePerAreaAndWork Query
{
return (area, workType) => {
// Lambda performing the query - or just return a method in the class that is the same signature as the delegate
}
}
}
Hooking this up by convention would mean using a type discovery system, like the one we have in Bifrost:
public class ValidationQueries
{
public ValidationQueries(IInstancesOf<IValidationQuery<>> validationQueries, IContainer container)
{
foreach( var query in validationQueries )
{
container.Bind(query.GetType().GetTypeInfo().BaseType.GenericArguments[0], query.Query);
}
}
}
You would then just need to get an instance of the ValidationQueries during startup to do it - in Bifrost terms; after configure is done or by creating a convention for it. The point is just to get the bindings right for the delegates.
In a validator - say, a CommandInputValidator, you would just then take a dependency to it:
public class RegisterTicketInputValidator : CommandBusinessValidator<RegisterTicket>
{
public RegisterTicketInputValidator(TicketMustBeUniquePerAreaAndWork ticketMustBeUniquePerAreaAndWork)
{
ModelRule().Must(ticketMustBeUniquePerAreaAndWork);
}
}