英文:
Parsing a json with datetimeoffset from PHP to C# results in wrong data
问题
I understand. Here's the translated content:
我从第三方收到一个复杂的JSON对象的webhook调用,其中包含一些类似于 `2023-04-05T14:13:47+0200` 的日期时间字段,所以当我用C#解析这个JSON时,结果是 `2023-04-05T14:13:47+02:00`,这会导致计算哈希码时出现问题。
这是JSON:
{
"message": "OK",
"code": 200,
"current_time": "2023-04-05T14:13:50+0200",
"order": {
"uuid": "45B32B3C-B01A-4D82-A03B-D5D9709DC92C",
"created": "2023-04-05T14:13:47+0200",
"created_from_client_timezone": "2023-04-05T14:13:47+0200",
"amount": 1000,
"currency": "978",
"paid": false,
"status": "CREATED",
"safe": true,
"refunded": 0,
"additional": null,
"service": "REDSYSPSD2",
"service_uuid": "F9D76AE8-DDBB-4F17-8074-C2DABEE0A919",
"customer": "test2222",
"cof_txnid": null,
"transactions": [],
"token": "345e77cc5a2616030ef5965d5513e1088adbd087b637da99eefc80f0729c943a26ef5e3a45b454819c62015e3d74f3282ecd2e1ab0b99a34de46d8aa37106a3d",
"ip": null,
"urls": {
"payment_card":"http:\/\/ws.paylands.loc\/su\/QY6cnT3MasUB",
"bizum":"http:\/\/ws.paylands.loc\/su\/0SWxTAvN0QkJ",
"3ds_tokenized":"http:\/\/ws.paylands.loc\/su\/3wEDqxIhjjsD"
},
"reference": null,
"dynamic_descriptor": "ëña,áds,ô ò,",
"threeds_data": null
},
"client": {
"uuid":"42B8CF56-A7D7-4D4A-8349-4E27263CB2D5"
},
"validation_hash": "414c8190e6b15ac767ff3217e994ef8687368ec8ebe6ab9ad570799d2f746cb7"
}
这是如何计算 `validation_hash` 的:
var jsonDe = JsonConvert.DeserializeObject<dynamic>(requestBody);
var signatureData = JsonConvert.SerializeObject(new Dictionary<string, object>
{
{ "order", jsonDe.order },
{ "client", jsonDe.client },
});
var signature = CalculateSHA256Hash(signatureData + settings.Signature);
if (signature != dto.ValidationHash)
{
serviceResult.AddError(0, _localizationRepository.Get("The request is invalid."));
return serviceResult;
}
static string CalculateSHA256Hash(string input)
{
using (SHA256 sha256Hash = SHA256.Create())
{
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
builder.Append(bytes[i].ToString("x2"));
}
return builder.ToString();
}
}
我尝试过几个转换器,但没有一个能解决不添加 `:` 到 DateTime 字段的问题。
我在DeserializeObject后修改了字段并删除了最后的 `:`,但那不是我喜欢的解决方案,所以是否有其他解决方案来解决这个问题?
另外,这是来自他们的PHP支持的示例:
https://onlinephp.io/c/4a0c8
英文:
I have a webhook call from a third party which is a complex JSON object, in this object, there are some datetime fields like this 2023-04-05T14:13:47+0200
, so when I parse this JSON with C#, the result is 2023-04-05T14:13:47+02:00
, and that causes an issue when calculating the hash code.
This is the JSON:
{
"message": "OK",
"code": 200,
"current_time": "2023-04-05T14:13:50+0200",
"order": {
"uuid": "45B32B3C-B01A-4D82-A03B-D5D9709DC92C",
"created": "2023-04-05T14:13:47+0200",
"created_from_client_timezone": "2023-04-05T14:13:47+0200",
"amount": 1000,
"currency": "978",
"paid": false,
"status": "CREATED",
"safe": true,
"refunded": 0,
"additional": null,
"service": "REDSYSPSD2",
"service_uuid": "F9D76AE8-DDBB-4F17-8074-C2DABEE0A919",
"customer": "test2222",
"cof_txnid": null,
"transactions": [],
"token": "345e77cc5a2616030ef5965d5513e1088adbd087b637da99eefc80f0729c943a26ef5e3a45b454819c62015e3d74f3282ecd2e1ab0b99a34de46d8aa37106a3d",
"ip": null,
"urls": {
"payment_card":"http:\/\/ws.paylands.loc\/su\/QY6cnT3MasUB",
"bizum":"http:\/\/ws.paylands.loc\/su\/0SWxTAvN0QkJ",
"3ds_tokenized":"http:\/\/ws.paylands.loc\/su\/3wEDqxIhjjsD"
},
"reference": null,
"dynamic_descriptor": "\u00eb\u00f1a,\u00e1ds,\u00f4 \u00f2,",
"threeds_data": null
},
"client": {
"uuid":"42B8CF56-A7D7-4D4A-8349-4E27263CB2D5"
},
"validation_hash": "414c8190e6b15ac767ff3217e994ef8687368ec8ebe6ab9ad570799d2f746cb7"
}
And this is how the validation_hash is calculated:
var jsonDe = JsonConvert.DeserializeObject<dynamic>(requestBody);
var signatureData = JsonConvert.SerializeObject(new Dictionary<string, object>
{
{ "order", jsonDe.order },
{ "client", jsonDe.client },
});
var signature = CalculateSHA256Hash(signatureData + settings.Signature);
if (signature != dto.ValidationHash)
{
serviceResult.AddError(0, _localizationRepository.Get("The request is invalid."));
return serviceResult;
}
static string CalculateSHA256Hash(string input)
{
using (SHA256 sha256Hash = SHA256.Create())
{
byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bytes.Length; i++)
{
builder.Append(bytes[i].ToString("x2"));
}
return builder.ToString();
}
}
I have tested several converters, but none of them could fix the issue of not adding :
to the DateTime field.
I modified the fields after the DeserializeObject and removed the last :
but that's not something I would prefer, so is there any other solution for this issue?
FYI, this is an example from their support with PHP:
https://onlinephp.io/c/4a0c8
答案1
得分: 3
如果你正在使用Newtonsoft的Json.NET(具有`JsonConvert`)-那么只需禁用自动的`DateTime`处理(我还建议从使用库提供的类型切换为动态JSON处理的类型):
```csharp
var requestBody = """
{
"current_time": "2023-04-05T14:13:50+0200",
"order": {
"uuid": "45B32B3C-B01A-4D82-A03B-D5D9709DC92C",
"created": "2023-04-05T14:13:47+0200",
"created_from_client_timezone": "2023-04-05T14:13:47+0200",
}
}
""";
var jsonDe = JsonConvert.DeserializeObject<JToken>(requestBody, new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None
});
Console.WriteLine(jsonDe["current_time"].ToString()); //2023-04-05T14:13:50+0200
Console.WriteLine(jsonDe["order"]["created_from_client_timezone"].ToString()); // 2023-04-05T14:13:47+0200
var signatureData = JsonConvert.SerializeObject(new Dictionary<string, object>
{
{ "order", jsonDe["order"] },
{ "client", jsonDe["client"] },
}); // {"order":{"uuid":"45B32B3C-B01A-4D82-A03B-D5D9709DC92C","created":"2023-04-05T14:13:47+0200","created_from_client_timezone":"2023-04-05T14:13:47+0200"},"client":null}
对于System.Text.Json
(如果你决定切换)-使用类似的API,例如JsonNode
(对我来说可以直接使用,不需要进行日期处理):
var jsonNode = JsonSerializer.Deserialize<JsonNode>(requestBody); // or JsonNode.Parse
Console.WriteLine(jsonNode["order"]["created_from_client_timezone"].ToString()); // 2023-04-05T14:13:47+0200
英文:
If you are using Newtonsoft's Json.NET (the one with JsonConvert
) - then simply disable the automatic DateTime
handling (also I recommend switching from using dynamic
to types exposed by the library for dynamic JSON handling):
var requestBody = """
{
"current_time": "2023-04-05T14:13:50+0200",
"order": {
"uuid": "45B32B3C-B01A-4D82-A03B-D5D9709DC92C",
"created": "2023-04-05T14:13:47+0200",
"created_from_client_timezone": "2023-04-05T14:13:47+0200",
}
}
""";
var jsonDe = JsonConvert.DeserializeObject<JToken>(requestBody, new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None
});
Console.WriteLine(jsonDe["current_time"].ToString()); //2023-04-05T14:13:50+0200
Console.WriteLine(jsonDe["order"]["created_from_client_timezone"].ToString()); // 2023-04-05T14:13:47+0200
var signatureData = JsonConvert.SerializeObject(new Dictionary<string, object>
{
{ "order", jsonDe["order"] },
{ "client", jsonDe["client"] },
}); // {"order":{"uuid":"45B32B3C-B01A-4D82-A03B-D5D9709DC92C","created":"2023-04-05T14:13:47+0200","created_from_client_timezone":"2023-04-05T14:13:47+0200"},"client":null}
For System.Text.Json
(if you decide to switch) - use similar API for example JsonNode
(works out of the box for me, no date handling happening):
var jsonNode = JsonSerializer.Deserialize<JsonNode>(requestBody); // or JsonNode.Parse
Console.WriteLine(jsonNode["order"]["created_from_client_timezone"].ToString()); // 2023-04-05T14:13:47+0200
P.S.
Be sure that indentation is also handled in the same way on both sides.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论