In my previous article, I focused on benchmarking Minimal APIs against Controllers.
Want to learn more about Minimal API Performance Benchmark? Read my post: Minimal API Performance Benchmark .
GitHub Repository
You can find the full project and source code on GitHub.
The journey continues, and the next step is to explore how to implement validation in Minimal APIs.
Key Consideration: No ModelState
One important thing to note is that Minimal APIs do not have a ModelState like controllers do. This raises the question: how can we validate a simple DTO?
A DTO (Data Transfer Object) is a simple object used to transfer data between different layers or parts of an application. It is primarily used to encapsulate data and reduce dependencies between components
Approach 1: Data Annotations
A common and straightforward approach is to decorate the model with DataAnnotation attributes. For example:
public class UserDto
{
[Required]
public string Name { get; set; }
[Required]
[Range(18, 99)]
public int Age { get; set; }
}
In the Minimal API, you can check for validation manually:
app.MapPost("minimalapi/create", ([FromBody] UserDto user) =>
{
var validationResults = new List<ValidationResult>();
var context = new ValidationContext(user);
if (!Validator.TryValidateObject(user, context, validationResults, true))
{
var errors = validationResults.ToDictionary(
v => v.MemberNames.FirstOrDefault() ?? "Error",
v => new string[] { v.ErrorMessage! });
return Results.BadRequest(new { Message = "Validation failed", Errors = errors });
}
return Results.Ok($"User {user.Name} created successfully!");
});
Approach 2: Middleware Validation
Another approach is to use middleware for validation. This allows us to centralize validation logic and keep endpoint handlers clean.
Example middleware:
Explanation of the ValidationMiddleware Code
This ASP.NET Core middleware validates checks if the request is POST or PUT, enables buffering, reads and **deserializes **the body into UserDto, validates it, and proceeds if valid. If validation fails, it returns a 400 Bad Request response with detailed validation errors in JSON format.
What is Middleware?
Middleware in ASP.NET Core is a component that processes HTTP requests and responses in the application's request pipeline. Middleware can:
- Handle authentication, logging, and error handling.
- Modify or reject requests before they reach controllers.
- Execute business logic before sending a response.
*How to Register Middleware in ASP.NET Core : *
app.UseMiddleware<ValidationMiddleware>();
Approach 3: FluentValidation
For a more robust and scalable validation mechanism, we can use FluentValidation.
Install FluentValidation:
dotnet add package FluentValidation.AspNetCore
Define a validator:
public class UserDtoValidator : AbstractValidator<UserDto>
{
public UserDtoValidator()
{
RuleFor(u => u.Name).NotEmpty().WithMessage("Name is required.");
RuleFor(u => u.Age).NotEmpty().InclusiveBetween(18, 99).WithMessage("Age must be between 18 and 99.");
}
}
Register FluentValidation in DI:
builder.Services.AddValidatorsFromAssemblyContaining<UserDtoValidator>();
Use the validator in the Minimal API:
app.MapPost("minimalapi/createV1", ([FromBody] UserDto user, IValidator<UserDto> validator) =>
{
var validationResult = validator.Validate(user);
if (!validationResult.IsValid)
{
var errors = validationResult.Errors
.GroupBy(e => e.PropertyName)
.ToDictionary(
g => g.Key,
g => g.Select(e => e.ErrorMessage).ToArray());
return Results.BadRequest(new { Message = "Validation failed", Errors = errors });
}
return Results.Ok($"User {user.Name} created successfully!");
});
Conclusion
Minimal APIs do not provide ModelState, so validation needs to be handled differently. Here are three approaches:
DataAnnotations: Simple but requires manual validation.
Middleware: Centralized validation but requires custom implementation.
FluentValidation: Scalable and clean, recommended for larger applications.
Each approach has its use case, but for a maintainable and scalable solution, FluentValidation is the best choice.
What are your thoughts? Have you tried different validation approaches in Minimal APIs?
References
1. DataAnnotations
- Microsoft Docs: Data Annotations - .NET
- Microsoft Docs: Validation with Data Annotations in ASP.NET Core
2. Middleware
- Microsoft Docs: Middleware in ASP.NET Core
- Microsoft Docs: Creating custom middleware in ASP.NET Core
Top comments (3)
I really would have preferred to see more code explanation. Also, it's difficult to read code when it's presented as an image. Consider leveraging syntax highlighting features in Markdown rather than using images.
Okay, I will do that soon. You can also take a look at the GitHub repository.
Hey Mike, I’ve updated this article with a short explanation . I hope it helps!
If it's still unclear, I can provide a more detailed article on Middleware and Fluent Validation.
Have a nice day!