I'm developing an application with ASP.NET Core 2.2. The solution contains two API projects. One is for private APIs and another one is for public APIs.
Both projects have code for model validation through a filter.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var errorKey = context.ModelState.Select(x => x.Key).FirstOrDefault();
var errorMessage = context.ModelState.SelectMany(x => x.Value.Errors).First().ErrorMessage;
var globalError = new GlobalErrorObject
{
Error = string.IsNullOrEmpty(errorMessage) ? $"The request contained at least one invalid parameter: {errorKey}" : errorMessage,
ErrorCode = HttpStatusCode.UnprocessableEntity
};
context.Result = new CustomActionResult(JsonConvert.SerializeObject(globalError), HttpStatusCode.UnprocessableEntity);
}
}
}
Now when I pass invalid JSON request data to my first API project, it gives me an invalid model state with errors in exception.
But passing the same invalid JSON to the second project behaves differently.
Startup.cs
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
Not sure what could be the issue and why the second API project is not throwing an exception or I have missed any configuration.
Edit-1 I have error handling middleware in both projects
public class RequestMiddleware
{
private readonly RequestDelegate _next;
public RequestMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
//preparing errorObject
await context.Response.WriteAsync(JsonConvert.SerializeObject(errorObject));
}
}
Edit-2: Configure method of both projects
Project 1:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
env.ConfigureNLog(_configuration);
var rateLimitingOptions = _configuration.GetSection("IpRateLimiting");
if (rateLimitingOptions != null && Convert.ToBoolean(rateLimitingOptions["EnableRateLimiting"]))
{
app.UseAppIpRateLimiting();
}
app.UseSecurityHeaders();
app.UseHttpsRedirection();
app.UseMultitenancy<Tenants>();
app.UseResponseCompression();
app.UseMiddleware(typeof(RequestMiddleware));
app.UseMvc();
app.UseSwagger();
app.UseSwaggerUI(
options =>
{
// build a swagger endpoint for each discovered API version
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
}
options.RoutePrefix = string.Empty;
});
//other services
}
Project 2:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
env.ConfigureNLog(_configuration);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMultitenancy<Tenants>();
app.UseResponseCompression();
app.UseMiddleware(typeof(RequestMiddleware));
app.UseMvc();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1");
c.RoutePrefix = string.Empty;
});
}