Validation
Validation is always a tough one because it’s a balance between being too strict and too loose. This middleware is designed to help you enforce the contract of your requests. It will validate the request before it gets to your handler. Unlike other middleware where you markup your handler with attributes, we use attributes on the contract itself. All of the exceptions, result types, and attributes for validation are in Shiny.Mediator.Contracts
We offer two flavours of validation frameworks in Microsoft Data Annotations & Fluent Validation.
Data Annotations
-
In your host startup, add the following to your mediator configuration:
services.AddShinyMediator(cfg => cfg.AddDataAnnotations()); -
Let’s mark your request contract up with some validation attributes as well as the required
ValidateAttribute
to trigger the middleware[Validate]public class MyRequest : IRequest // works with results as well{[Required]public string Name { get; set; }[Range(1, 100)]public int Age { get; set; }} -
Now set and pass your requests just like normal. Look at Usage below to see how to work with the validation results.
Fluent Validation
-
Install the
Shiny.Mediator.FluentValidation
packageTerminal window dotnet add package Shiny.Mediator.FluentValidation -
In your host startup, add the following to your mediator configuration
services.AddShinyMediator(cfg => cfg.AddFluentValidation()); -
Mark your request contract with the
ValidateAttribute
:[Validate]public class MyRequest : IRequest; // works with results as well{public string? Name { get; set; }} -
Now create a validator for your request using fluent validation rules
public class MyRequestValidator : AbstractValidator<MyRequest>{public MyRequestValidator(){RuleFor(x => x.Name).NotEmpty();}} -
Now set and pass your requests just like normal. Look at Usage below to see how to work with the validation results.
Usage
Once you have a validation middleware installed and your contracts marked, you have two options for how to manage the validation results. You can either handle the exceptions or you can check the ValidationResult
object that is returned from the IMediator.Send
method.
Contract with Void Result or Your Result Type
Let’s take a look at some sample contracts
// validation properties left out for brevity[Validate]public class MyRequest : IRequest;
[Validate]public class MyRequestResult : IResult<MyResult>;
Now, the send off to mediator
IMediator mediator; // injectedtry{ mediator.Send(new MyRequest()); // or Request(new MyRequestResult());}catch (ValdidateException ex){ // contains a dictionary a property names with the error message(s) for each property ex.Result.Errors;}
Contract with ValidateResult return
If you think exceptions are barbaric, you can also check the ValidationResult
object in place of your result contract
// validation properties left out for brevity[Validate]public class MyRequest : IRequest<ValidationResult>;
and now the send off to mediator
IMediator mediator; // injectedvar result = await mediator.Request(new MyRequest());
// contains a dictionary a property names with the error message(s) for each propertyif (!result.IsValid) result.Errors;