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

asp.net-web-api – Web API / JsonMediaTypeFormatter接受无效

发布时间:2020-12-16 06:23:17 所属栏目:asp.Net 来源:网络整理
导读:我有以下型号: public class Resource{ [DataMember(IsRequired = true)] [Required] public bool IsPublic { get; set; } [DataMember(IsRequired = true)] [Required] public ResourceKey ResourceKey { get; set; }}public class ResourceKey{ [StringLe
我有以下型号:

public class Resource
{
    [DataMember(IsRequired = true)]
    [Required]
    public bool IsPublic { get; set; }

    [DataMember(IsRequired = true)]
    [Required]
    public ResourceKey ResourceKey { get; set; }
}

public class ResourceKey
{
    [StringLength(50,MinimumLength = 1)]
    [Required]
    public string SystemId { get; set; }

    [StringLength(50,MinimumLength = 1)]
    [Required]
    public string SystemDataIdType { get; set; }

    [StringLength(50,MinimumLength = 1)]
    [Required]
    public string SystemEntityType { get; set; }

    [StringLength(50,MinimumLength = 1)]
    [Required]
    public string SystemDataId { get; set; }
}

我有以下操作方法签名:

public HttpResponseMessage PostResource(Resource resource)

我在正文中发送了以下带有JSON的请求(属性“IsPublic”的故意无效值):

Request Method:POST
Host: localhost:63307
Connection: keep-alive
Content-Length: 477
User-Agent: Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.22 (KHTML,like Gecko) Chrome/25.0.1364.97 Safari/537.22
Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
Content-Type: application/json
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

{
    "IsPublic": invalidvalue,"ResourceKey":{     
        "SystemId": "asdf","SystemDataIdType": "int","SystemDataId": "Lorem ipsum","SystemEntityType":"EntityType"
    },}

这是无效的JSON – 通过JSONLint运行它并告诉您:

Parse error on line 2:

{ “IsPublic”: invalidvalue,

……………..^ Expecting ‘STRING’,‘NUMBER’,‘NULL’,‘TRUE’,‘FALSE’,‘{‘,‘[‘

ModelState.IsValid属性为’true’ – 为什么???

此外,格式化程序似乎放弃了反序列化,而只是将’resource’参数传递给action方法,而不是抛出验证错误!

请注意,如果我为其他属性添加了无效值,例如,也会发生这种情况.代:

"SystemId": notAnObjectOrLiteralOrArray

但是,如果我发送以下JSON与“SystemId”属性的特殊未定义值:

{
    "IsPublic": true,ResourceKey:{       
        "SystemId": undefined,}

然后我得到以下,合理的,异常抛出:

Exception Type: Newtonsoft.Json.JsonReaderException
Message: "Error reading string. Unexpected token: Undefined. Path 'ResourceKey.SystemId',line 4,position 24."
Stack Trace: " at Newtonsoft.Json.JsonReader.ReadAsStringInternal() 
at Newtonsoft.Json.JsonTextReader.ReadAsString() 
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader,JsonContract contract,Boolean hasConverter) 
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject,JsonReader reader,JsonObjectContract contract,JsonProperty member,String id)"

那么:在Newtonsoft.Json库中发生了什么导致看起来像是部分JSON验证???

PS:可以将JSON名称/值对发布到Web API,而无需将名称括在引号中…

{
    IsPublic: true,ResourceKey:{       
        SystemId: "123",SystemDataIdType: "int",SystemDataId: "Lorem ipsum",SystemEntityType:"EntityType"
    },}

这也是无效的JSON!

解决方法

好的 – 所以看来部分问题是由我自己造成的.

我在控制器上有两个过滤器:

>检查是否有任何空操作参数传递给操作方法,如果是,则返回“400 Bad Request”响应,规定参数不能为null.
>一个ModelState检查过滤器,它检查ModelState的错误,如果找到任何错误,则在“400错误请求”响应中返回它们.

我犯的错误是在模型状态检查过滤器之前放置null参数过滤器.

在模型绑定之后,序列化将在第一个JSON示例中正确失败,并且会将相关的序列化异常放在ModelState中,并且action参数将保持为null,这是正确的.

但是,由于第一个过滤器检查空参数然后返回“404错误请求”响应,因此ModelState过滤器从未启动…

因此,似乎验证没有发生,事实上确实如此,但结果却被忽略了!

重要说明:模型绑定期间发生的序列化异常放在ModelState KeyValue对的“异常”属性中…不在ErrorMessage属性中!

为了帮助其他人进行这种区分,这里是我的ModelValidationFilterAttribute:

public class ModelValidationFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.ModelState.IsValid) return;

        // Return the validation errors in the response body.
        var errors = new Dictionary<string,IEnumerable<string>>();
        foreach (KeyValuePair<string,ModelState> keyValue in actionContext.ModelState)
        {
            var modelErrors = keyValue.Value.Errors.Where(e => e.ErrorMessage != string.Empty).Select(e => e.ErrorMessage).ToList();
            if (modelErrors.Count > 0)
                errors[keyValue.Key] = modelErrors;

            // Add details of any Serialization exceptions as well
            var modelExceptions = keyValue.Value.Errors.Where(e => e.Exception != null).Select(e => e.Exception.Message).ToList();
            if (modelExceptions.Count > 0)
                errors[keyValue.Key + "_exception"] = modelExceptions;
        }
        actionContext.Response =
            actionContext.Request.CreateResponse(HttpStatusCode.BadRequest,errors);
    }
}

这是动作方法,过滤器的顺序正确:

[ModelValidationFilter]
    [ActionArgNotNullFilter]
    public HttpResponseMessage PostResource(Resource resource)

现在,以下JSON结果如下:

{
    "IsPublic": invalidvalue,} 

{
    "resource.IsPublic_exception": [(2)
    "Unexpected character encountered while parsing value: i. Path 'IsPublic',line 2,position 21.","Unexpected character encountered while parsing value: i. Path 'IsPublic',position 21."
    ]-
}

但是,所有这些都无法解释为什么JSONMediaTypeFormatter仍然会解析无效JSON,例如它不要求名称是字符串.

(编辑:李大同)

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

    推荐文章
      热点阅读