网页API / JsonMediaTypeFormatter接受无效JSON并传递null参数行动 [英] Web API/JsonMediaTypeFormatter accepts Invalid JSON and passes null argument to action

查看:773
本文介绍了网页API / JsonMediaTypeFormatter接受无效JSON并传递null参数行动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下型号:

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

我有以下操作方法签名:

I have the following action method signature:

public HttpResponseMessage PostResource(Resource resource)

我发送使用JSON在身体下面的请求(财产故意无效值IsPublic):

I send the following request with JSON in the body (an intentionally invalid value for property "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运行它,它会告诉你:

This is invalid JSON - run it through JSONLint and it tells you:

第2行解析错误:

{IsPublic:一个InvalidValue,

{ "IsPublic": invalidvalue,

................. ^期待STRING,NUMBER','NULL','真','假','{','['

.................^ Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '['

的ModelState.IsValid属性为'真' - 为什么???

此外,而不是抛出一个验证错误,格式化似乎放弃反序列化和简单地将资源的说法来操作方法为空!

Also, instead of throwing a validation error, the formatter seems to give up on deserializing and simply passes the 'resource' argument to the action method as null!

请注意,这也正好,如果我把在其他属性的值无效,例如代:

Note that this also happens if I put in an invalid value for other properties, e.g. substituting:

"SystemId": notAnObjectOrLiteralOrArray

不过,如果我发送以下JSON具有特殊的未定义作为SYSTEMID属性值:

However, if I send the following JSON with a special undefined value for the "SystemId" property:

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

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

Then I get the following, reasonable, exception thrown:

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)"

SO:什么是在Newtonsoft.Json库导致什么似乎像部分JSON验证???怎么回事

SO: what is going on in the Newtonsoft.Json library which results in what seems like partial JSON Validation???

PS:这是可以张贴的JSON名称/值对到Web API无引号引起来的名字......

PS: It is possible to post JSON name/value pairs to the Web API without enclosing the names in quotes...

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

这也是无效的JSON!

This is also invalid JSON!

推荐答案

确定 - 所以它出现的问题的一部分是由我自己做造成的。

OK - so it appears that part of the problem was caused by my own doing.

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

I had two filters on the controller:


  1. 检查是否有被传递到操作方法,如果是这样的空操作参数,返回400错误的请求的响应,规定的参数不能为null。

  2. 其中检查ModelState中的错误和如果找到,在400错误的请求的响应返回他们的ModelState检查过滤器。

我犯的错误是模型状态检查过滤器前把空参数过滤器。

The mistake I made was to put the null argument filter before the model state checking filter.

后,序列化可以正确失败的第一个JSON的例子,并会放在ModelState中的相关序列的异常和操作参数将保持为空,这是理所当然的。

After Model Binding, the serialization would fail correctly for the first JSON example, and would put the relevant serialization exception in ModelState and the action argument would remain null, rightfully so.

然而,由于第一过滤器检查空参数,然后返回404错误的请求响应,过滤器的ModelState从未在踢...

However, since the first filter was checking for null arguments and then returning a "404 Bad Request" response, the ModelState filter never kicked in...

因此​​,它似乎验证没有发生,而事实上它是,但结果被忽略了!

Hence it seemed that validation was not taking place, when in fact it was, but the results were being ignored!

重要提示:序列化过程中的异常模型绑定都放在ModelState中键值对的值的'例外'属性...不是在ErrorMessage属性中发生

IMPORTANT: Serialization exceptions that happen during Model Binding are placed in the 'Exception' property of the ModelState KeyValue pair Value...NOT in the ErrorMessage property!

要帮助其他有这种区别,这里是我的ModelValidationFilterAttribute:

To help others with this distinction, here is my 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);
    }
}

和这里的操作方法,用正确的顺序过滤器:

And here is the action method, with the filters in the correct order:

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

所以,现在,下面的JSON结果:

So now, the following JSON results in:

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

{
    "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', line 2, position 21."
    ]-
}

然而,这一切并不能解释为什么无效JSON仍然由JsonMediaTypeFormatter例如解析它不需要名称是字符串。

However, all of this does not explain why invalid JSON is still parsed by the JsonMediaTypeFormatter e.g. it does not require that names be strings.

这篇关于网页API / JsonMediaTypeFormatter接受无效JSON并传递null参数行动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆