Skip to content

REQUEST - Request Contract 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

  1. In your host startup, add the following to your mediator configuration:

    services.AddShinyMediator(cfg => cfg.AddDataAnnotations());
  2. 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; }
    }
  3. Now set and pass your requests just like normal. Look at Usage below to see how to work with the validation results.

Fluent Validation

  1. Install the Shiny.Mediator.FluentValidation package

    Terminal window
    dotnet add package Shiny.Mediator.FluentValidation
  2. In your host startup, add the following to your mediator configuration

    services.AddShinyMediator(cfg => cfg.AddFluentValidation());
  3. Mark your request contract with the ValidateAttribute:

    [Validate]
    public class MyRequest : IRequest; // works with results as well
    {
    public string? Name { get; set; }
    }
  4. Now create a validator for your request using fluent validation rules

    public class MyRequestValidator : AbstractValidator<MyRequest>
    {
    public MyRequestValidator()
    {
    RuleFor(x => x.Name).NotEmpty();
    }
    }
  5. 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; // injected
try
{
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; // injected
var result = await mediator.Request(new MyRequest());
// contains a dictionary a property names with the error message(s) for each property
if (!result.IsValid)
result.Errors;