加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

.net – 如何从ModelState键中删除前缀?

发布时间:2020-12-16 00:46:16 所属栏目:asp.Net 来源:网络整理
导读:例如,有一个Web Api操作方法: public HttpMessageResponse Post(UserDto userDto){ if (!this.ModelState.IsValid) { return this.Request.CreateErrorResponse( HttpStatusCode.BadRequest,this.ModelState); } // ...} 客户端发送以下请求: HTTP POST:
例如,有一个Web Api操作方法:
public HttpMessageResponse Post(UserDto userDto)
{
    if (!this.ModelState.IsValid)
    {
        return this.Request.CreateErrorResponse(
            HttpStatusCode.BadRequest,this.ModelState);
    }

    // ...
}

客户端发送以下请求:

HTTP POST: /api/user
{ "username": "me","password": "Pa$sw0rd" }

并得到回应:

HTTP 201/Created:
{ "message": "Your request is invalid.","modelState": { "userDto.Password": "Your password is too strong." } }

默认情况下,action方法通过使用action方法中使用的参数名前缀模型错误来公开实现细节。如果客户端应用程序在清理模型错误,然后是服务器端代码更改(例如,您用Post(UserDto dto)替换了Post(UserDto userDto))签名时,会重新编码此前缀名称,并且所有客户端应用程序都停止工作。

这就是为什么你需要确保这个前缀在服务器端被删除。问题是如何正确地做,没有使事情复杂化。例如,您可以创建一个自定义序列化程序,并在序列化期间删除这些前缀。但是为了做到这一点,你需要知道模型参数的名称,调用代码可能看起来像这样:

public HttpMessageResponse Post(UserDto userDto)
{
    if (!this.ModelState.IsValid)
    {
        return this.Request.CreateCustomErrorResponse(
            HttpStatusCode.BadRequest,this.ModelState,modelName: "userDto");
    }

    // ...
}

解决方法

第一部分:

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

我同意将参数名称作为所有模型状态错误的前缀都不是很大的行为。幸运的是,具有此行为的服务是可替换的。你只需要一个自定义IBodyModelValidator。这是它的样子(使用Decorator模式让默认服务做大部分工作):

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);
    }
}

然后,用你的包装默认服务:

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

对于第二部分:

elso replace “modelState” with “errors”

目前的原因是“modelState”是您当前的代码:

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

有效地执行以下操作:

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

由于HttpError被序列化,并且它有一个名为“ModelState”的属性,这就是您在响应中看到的。

如果要使用不同的属性名称,可以使用自定义错误类:

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; }
}

然后使用此错误类型创建您的响应,而不是HttpError:

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

PrettyHttpError和PrefixlessBodyModelValidator的组合给出了您请求的输出。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读