Business Rule Validation
Validate PublicationYear
In addition to basic request validation, it is common to validate business rules against static values or values from database.
Let's validate that PublicationYear has a minimum value of 1900 and max value of current year.
csharp
[HttpPost]
public IActionResult Create(CreateBookRequest request)
{
logger.LogInformation("BookController.Create - Request {@request}", request");
if (request.PublicationYear < 1900 || request.PublicationYear > DateTime.UtcNow.Year)
{
throw new ValidationException("Publication Year must be between 1990 and 2025");
}
//...
}
Test the API, the response is not consumable by frontend or mobile to show a readable message.
To get a similar response as basic validation, we can introduce an error middleware.
json
{
"title": "",
"status": "",
"errors": "",
}
Add ErrorMiddleware
First, add Newtonsoft nuget package, it's used to serialise objects into JSON and vice versa.
Next, in Dtos folder, add ErrorResponse.cs
csharp
public class ErrorResponse
{
public string Title { get; set; }
public int Status { get; set; }
public Dictionary<string, List<string>> Errors { get; set; }
public ErrorResponse(int code, string message)
{
Title = message;
Status = code;
Errors = new Dictionary<string, List<string>>();
}
}
In Utilities folder, add ErrorMiddleware.cs
csharp
public class ErrorMiddleware
{
private readonly RequestDelegate _next;
public ErrorMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private Task HandleExceptionAsync(HttpContext context, Exception exception)
{
//exception = exception.Get();
var statusCode = HttpStatusCode.InternalServerError;
if (exception is ValidationException)
{
Log.Information(exception.Message);
statusCode = HttpStatusCode.UnprocessableContent;
}
else if (exception is AuthenticationException)
{
Log.Error(exception.Message);
statusCode = HttpStatusCode.Unauthorized;
}
else
{
Log.Fatal(exception.Message);
Log.Fatal(exception.StackTrace);
}
var camelCaseSerializerSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var errorResponse = new ErrorResponse((int)statusCode, exception.Message);
var result = JsonConvert.SerializeObject(errorResponse, camelCaseSerializerSettings);
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)400;
return context.Response.WriteAsync(result);
}
}
In Program.cs, add
csharp
//...
app.UseMiddleware(typeof(ErrorMiddleware)); //add this
app.MapControllers();
//...