Search code examples
exceptionlocalizationasp.net-core-webapimodel-bindingjson-deserialization

How to localize exception message for Json deserialization? An invalid parameter was passed when requesting the interface?


My development environment is.Net7 WebApi (out of the box)

Below is the relevant code. DataAnnotations I have implemented localization.

using System.ComponentModel.DataAnnotations;

namespace WebApi.Dtos
{
    public class UserRegistrationDto
    {
        [Required(ErrorMessage = "UserNameRequiredError")]
        [MinLength(6, ErrorMessage = "UserNameMinLengthError")]
        [MaxLength(30, ErrorMessage = "UserNameMaxLengthError")]
        public required string UserName { get; set; }

        [Required(ErrorMessage = "PasswordRequiredError")]
        public required string Password { get; set; }
    }
}
[HttpPost]
public async Task<IActionResult> RegisterUser([FromBody] UserRegistrationDto userRegistration)
{
    return Ok(1);
    // IdentityResult userResult = await _userManager.CreateAsync(new IdentityUser { UserName = userRegistration.UserName }, userRegistration.Password);

    // return userResult.Succeeded ? StatusCode(201) : BadRequest(userResult);
}

When the request body is invalid JSON.

curl -X 'POST' \
  'https://localhost:7177/Authenticate/RegisterUser' \
  -H 'accept: */*' \
  -H 'Api-Version: 1.0' \
  -H 'Content-Type: application/json' \
  -d '{}'
{
    "$": [
        "JSON deserialization for type 'WebApi.Dtos.UserRegistrationDto' was missing required properties, including the following: userName, password"
    ],
    "userRegistration": [
        "The userRegistration field is required."
    ]
}

When the request body is Empty.

curl -X 'POST' \
  'https://localhost:7177/Authenticate/RegisterUser' \
  -H 'accept: */*' \
  -H 'Api-Version: 1.0' \
  -H 'Content-Type: application/json' \
  -d ''
{
    "": [
        "The userRegistration field is required."
    ]
}

It throws exception information before binding to DTO, can this exception information be localized? If not, is it possible to capture this information for secondary processing, such as returning a fixed JSON format?

I've tried this in the Program.cs entry file, but it's not ideal.

.ConfigureApiBehaviorOptions(options =>
{
    options.SuppressModelStateInvalidFilter = false;
    options.InvalidModelStateResponseFactory = context =>
    {
        bool knownExceptions = context.ModelState.Values.SelectMany(x => x.Errors).Where(x => x.Exception is JsonException || (x.Exception is null && String.IsNullOrWhiteSpace(x.ErrorMessage) == false)).Count() > 0;
        if (knownExceptions)
        {
            return new BadRequestObjectResult(new { state = false, message = localizer["InvalidParameterError"].Value });
        }
        // ...
        return new BadRequestObjectResult(context.ModelState);
    };
})

I have also tried this method, but I can’t capture the exception information that failed when binding DTO alone. They will appear together with the ErrorMessage exception information in DTO like the above writing method.

.AddControllers(options =>
{
    // options.Filters.Add(...);
    // options.ModelBindingMessageProvider // This doesn't work either, it seems to support [FromForm]
})

Back to the topic, can it be localized? Or there is something wrong with the code. I just learned .Net not long ago. Most of the information I learned came from search engines and official documents. Thanks in advance.


Solution

  • Use the following method.

    .AddControllers(options =>
    {
        // options.ModelBindingMessageProvider.Set...
    })
    

    It seems that the exception of JSON deserialization caused by passing invalid parameters can only be eliminated on the client side. So far it seems I haven't found a localization for this exception, but it's not very important to me at the moment. Thanks @XinranShen for helping point me in the right direction.