How to remove prefixes from ModelState keys?

后端 未结 1 2004
挽巷
挽巷 2021-01-31 18:19

For example, there is a Web Api action method:

public HttpMessageResponse Post(UserDto userDto)
{
    if (!this.ModelState.IsValid)
    {
        return this.Req         


        
相关标签:
1条回答
  • 2021-01-31 18:55

    For the first part:

    Also error messages returned to a client shouldn't contain those prefixes

    I agree having the parameter name as a prefix on all model state errors isn't great behavior. Fortunately, the service that has this behavior is replaceable. You just need to have a custom IBodyModelValidator. Here's what it would look like (using the Decorator pattern to let the default service do most of the work):

    public class PrefixlessBodyModelValidator : IBodyModelValidator
    {
        private readonly IBodyModelValidator _innerValidator;
    
        public PrefixlessBodyModelValidator(IBodyModelValidator innerValidator)
        {
            if (innerValidator == null)
            {
                throw new ArgumentNullException("innerValidator");
            }
    
            _innerValidator = innerValidator;
        }
    
        public bool Validate(object model, Type type, ModelMetadataProvider metadataProvider, HttpActionContext actionContext, string keyPrefix)
        {
            // Remove the keyPrefix but otherwise let innerValidator do what it normally does.
            return _innerValidator.Validate(model, type, metadataProvider, actionContext, String.Empty);
        }
    }
    

    Then, wrap the default service with yours:

    config.Services.Replace(typeof(IBodyModelValidator), new PrefixlessBodyModelValidator(config.Services.GetBodyModelValidator()));
    

    For the second part:

    elso replace "modelState" with "errors"

    The reason it currently says "modelState" is your current code:

    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
    

    Is effectively doing the following:

    HttpError error = new HttpError(ModelState, false);
    return Request.CreateResponse(HttpStatusCode.BadRequest, error);
    

    Since HttpError is being serialized, and it has a property named "ModelState", that's what you see in the response.

    If you want a different property name, you can use a custom error class:

    public class PrettyHttpError
    {
        public PrettyHttpError(ModelStateDictionary modelState)
        {
            Message = "Your request is invalid.";
            Errors = new Dictionary<string, IEnumerable<string>>();
    
            foreach (var item in modelState)
            {
                var itemErrors = new List<string>();
                foreach (var childItem in item.Value.Errors)
                {
                    itemErrors.Add(childItem.ErrorMessage);
                }
                Errors.Add(item.Key, itemErrors);
            }
        }
    
        public string Message { get; set; }
    
        public IDictionary<string, IEnumerable<string>> Errors { get; set; }
    }
    

    And then create your response with this error type instead of HttpError:

    PrettyHttpError error = new PrettyHttpError(ModelState);
    return Request.CreateResponse(HttpStatusCode.BadRequest, error);
    

    The combination of PrettyHttpError and PrefixlessBodyModelValidator gives the output you requested.

    0 讨论(0)
提交回复
热议问题