gpt4 book ai didi

asp.net-web-api - Web API/JsonMediaTypeFormatter 接受无效的 JSON 并将 null 参数传递给操作

转载 作者:行者123 更新时间:2023-12-02 01:32:08 26 4
gpt4 key购买 nike

我有以下模型:

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” - 为什么???

此外,格式化程序似乎放弃了反序列化,而不是抛出验证错误,而是简单地将“资源”参数作为 null 传递给操作方法!

请注意,如果我为其他属性输入无效值,例如,也会发生这种情况。替换:

"SystemId": notAnObjectOrLiteralOrArray

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

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

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

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 验证???

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

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

这也是无效的 JSON!

最佳答案

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

我的 Controller 上有两个过滤器:

  1. 检查是否有任何 null 操作参数传递给操作方法,如果有,则返回“400 Bad Request”响应,规定该参数不能为 null。
  2. 一个 ModelState 检查过滤器,用于检查 ModelState 的错误,如果发现任何错误,则在“400 Bad Request”响应中返回它们。

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

模型绑定(bind)后,第一个 JSON 示例的序列化将正确失败,并将相关序列化异常放入 ModelState 中,并且操作参数将保持为空,这是理所当然的。

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

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

重要:模型绑定(bind)期间发生的序列化异常将放置在 ModelState KeyValue 对 Value 的“Exception”属性中...而不是放置在 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,
"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."
]-
}

但是,所有这些并不能解释为什么 JsonMediaTypeFormatter 仍然会解析无效的 JSON,例如它不要求名称是字符串。

关于asp.net-web-api - Web API/JsonMediaTypeFormatter 接受无效的 JSON 并将 null 参数传递给操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15094314/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com