2

I need custom message for my request.

Currently I am passing below request json from postman

{
 "countryid": "14sdsads02"
}

but my model is

public class model
{
 public int countryid {get;set;}
}

When pass request from postman, I am getting below error

{
 "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
 "title": "One or more validation errors occurred.",
 "status": 400,
 "traceId": "|21793cf-495c68ddbc92ab35.",
 "errors": {
 "$.countryid": [
 "The JSON value could not be converted to System.Int32. Path: $.countryid | LineNumber: 1 | BytePositionInLine: 29."
 ]
 }
}

But instead of this, I need custom error in my web api. How can I achieve this?

Peter Csala
23.5k16 gold badges51 silver badges96 bronze badges
asked Dec 12, 2020 at 6:45
3
  • @PeterCsala . Please under stand i know what is type difference. Only vulnerability purpose i need to stop my property exposing. So how my server level response to customize. Commented Dec 12, 2020 at 11:34
  • Sorry, I misunderstood your question. I left a solution proposal with the desired behaviour. Commented Dec 12, 2020 at 12:16
  • What is the format that you want to custom error?For how to custom error message you could refer to:stackoverflow.com/a/62989600/11398810. Commented Dec 14, 2020 at 6:34

2 Answers 2

2

If you want to define a custom response in case of 400 then you can do the followings:

The handler

In order to catch the model binding errors you have to wire up a handler for the ApiBehaviorOptions's InvalidModelStateResponseFactory (1).

The required delegate is quite generic: Func<ActionContext, IActionResult>. So, first let's create an interface for this:

public interface IModelBindingErrorHandler
{
 IActionResult HandleInvalidModelState(ActionContext context);
}

Here is a simple handler implementation:

public class ModelBindingErrorHandler : IModelBindingErrorHandler
{
 private ICorrelationContextAccessor correlationContextAccessor;
 private ILogger logger;
 public ModelBindingErrorHandler(ICorrelationContextAccessor correlationContextAccessor, ILogger logger)
 {
 this.correlationContextAccessor = correlationContextAccessor;
 this.logger = logger;
 }
 public IActionResult HandleInvalidModelState(ActionContext context)
 {
 string correlationId = correlationContextAccessor.CorrelationContext?.CorrelationId;
 var modelErrors = context.ModelState
 .Where(stateEntry => stateEntry.Value.Errors.Any())
 .Select(stateEntry => new InvalidData
 {
 FieldName = stateEntry.Key,
 Errors = stateEntry.Value.Errors.Select(error => error.ErrorMessage).ToArray()
 });
 logger.LogError("The request contained malformed input.", modelErrors);
 var responseBody = new GlobalErrorModel
 {
 ErrorMessage = "Sorry, the request contains invalid data. Please revise.", 
 ErrorTracingId = correlationId
 };
 
 return new BadRequestObjectResult(responseBody);
 }
}

The helper classes

public class GlobalErrorModel
{
 public string ErrorMessage { get; set; }
 public string ErrorTracingId { get; set; }
}
public class InvalidData
{
 public string FieldName { get; set; }
 public string[] Errors { get; set; }
 public override string ToString() => $"{FieldName}: {string.Join("; ", Errors)}";
}

Self-registration

public static class ModelBindingErrorHandlerRegister
{
 /// <summary>
 /// This method should be called after <b>AddControllers();</b> call.
 /// </summary>
 public static IServiceCollection AddModelBinderErrorHandler(this IServiceCollection services)
 {
 return AddModelBinderErrorHandler<ModelBindingErrorHandler>(services);
 }
 /// <summary>
 /// This method can be used to register a custom Model binder's error handler.
 /// </summary>
 /// <typeparam name="TImpl">A custom implementation of <see cref="IModelBindingErrorHandler"/></typeparam>
 public static IServiceCollection AddModelBinderErrorHandler<TImpl>(this IServiceCollection services)
 where TImpl : class, IModelBindingErrorHandler
 {
 services.AddSingleton<IModelBindingErrorHandler, TImpl>();
 var serviceProvider = services.BuildServiceProvider();
 var handler = serviceProvider.GetService<IModelBindingErrorHandler>();
 services.PostConfigure((ApiBehaviorOptions options) =>
 options.InvalidModelStateResponseFactory = handler.HandleInvalidModelState);
 return services;
 }
}

Usage

public partial class Startup
{
 private readonly IConfiguration Configuration;
 public Startup(IConfiguration configuration)
 {
 Configuration = configuration;
 }
 public void ConfigureServices(IServiceCollection services)
 {
 services.AddControllers()
 .AddNewtonsoftJson();
 
 //Omited for brevity
 
 services.AddModelBinderErrorHandler();
 }
 
 //Omited for brevity
}
answered Dec 12, 2020 at 12:15

2 Comments

Thanks for your answer. It is worked for me. Bit I didn't understand what is correlationContextAccessor and what is package for this in .net core 3.1
@valuesoft It is an external nuget package, called CorrelationId. It helps you to create ids in distributed tracing.
-1

A simple solution is to change type of countryid from int to string in your model"

public class model
{
 public string countryid {get;set;}
}

Then in your controller check if the value is convertible to int or not. If not, return a customized BadRequest response:

int countryid;
if (!int.TryParse(model.countryid, out countryid))
 return BadRequest("Your customized error message");
answered Dec 13, 2020 at 10:33

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.