从PHP解析带有datetimeoffset的JSON到C#会导致错误的数据。

huangapple go评论71阅读模式
英文:

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:

{
&quot;message&quot;: &quot;OK&quot;,
&quot;code&quot;: 200,
&quot;current_time&quot;: &quot;2023-04-05T14:13:50+0200&quot;,
&quot;order&quot;: {
&quot;uuid&quot;: &quot;45B32B3C-B01A-4D82-A03B-D5D9709DC92C&quot;,
&quot;created&quot;: &quot;2023-04-05T14:13:47+0200&quot;,
&quot;created_from_client_timezone&quot;: &quot;2023-04-05T14:13:47+0200&quot;,
&quot;amount&quot;: 1000,
&quot;currency&quot;: &quot;978&quot;,
&quot;paid&quot;: false, 
&quot;status&quot;: &quot;CREATED&quot;,
&quot;safe&quot;: true,
&quot;refunded&quot;: 0,
&quot;additional&quot;: null,
&quot;service&quot;: &quot;REDSYSPSD2&quot;,
&quot;service_uuid&quot;: &quot;F9D76AE8-DDBB-4F17-8074-C2DABEE0A919&quot;,
&quot;customer&quot;: &quot;test2222&quot;,
&quot;cof_txnid&quot;: null,
&quot;transactions&quot;: [],
&quot;token&quot;: &quot;345e77cc5a2616030ef5965d5513e1088adbd087b637da99eefc80f0729c943a26ef5e3a45b454819c62015e3d74f3282ecd2e1ab0b99a34de46d8aa37106a3d&quot;,
&quot;ip&quot;: null,
&quot;urls&quot;: { 
&quot;payment_card&quot;:&quot;http:\/\/ws.paylands.loc\/su\/QY6cnT3MasUB&quot;,
&quot;bizum&quot;:&quot;http:\/\/ws.paylands.loc\/su\/0SWxTAvN0QkJ&quot;,
&quot;3ds_tokenized&quot;:&quot;http:\/\/ws.paylands.loc\/su\/3wEDqxIhjjsD&quot;
},
&quot;reference&quot;: null,
&quot;dynamic_descriptor&quot;: &quot;\u00eb\u00f1a,\u00e1ds,\u00f4 \u00f2,&quot;,
&quot;threeds_data&quot;: null
},
&quot;client&quot;: {
&quot;uuid&quot;:&quot;42B8CF56-A7D7-4D4A-8349-4E27263CB2D5&quot;
},
&quot;validation_hash&quot;: &quot;414c8190e6b15ac767ff3217e994ef8687368ec8ebe6ab9ad570799d2f746cb7&quot;
}

And this is how the validation_hash is calculated:

var jsonDe = JsonConvert.DeserializeObject&lt;dynamic&gt;(requestBody);
var signatureData = JsonConvert.SerializeObject(new Dictionary&lt;string, object&gt;
{
{ &quot;order&quot;, jsonDe.order },
{ &quot;client&quot;, jsonDe.client },
});
var signature = CalculateSHA256Hash(signatureData + settings.Signature);
if (signature != dto.ValidationHash)
{
serviceResult.AddError(0, _localizationRepository.Get(&quot;The request is invalid.&quot;));
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 &lt; bytes.Length; i++)
{
builder.Append(bytes[i].ToString(&quot;x2&quot;));
}
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 = &quot;&quot;&quot;
{
    &quot;current_time&quot;: &quot;2023-04-05T14:13:50+0200&quot;,
    &quot;order&quot;: {
                &quot;uuid&quot;: &quot;45B32B3C-B01A-4D82-A03B-D5D9709DC92C&quot;,
                &quot;created&quot;: &quot;2023-04-05T14:13:47+0200&quot;,
                &quot;created_from_client_timezone&quot;: &quot;2023-04-05T14:13:47+0200&quot;,
           }
}
&quot;&quot;&quot;;
var jsonDe = JsonConvert.DeserializeObject&lt;JToken&gt;(requestBody, new JsonSerializerSettings
{
    DateParseHandling = DateParseHandling.None
});
Console.WriteLine(jsonDe[&quot;current_time&quot;].ToString()); //2023-04-05T14:13:50+0200
Console.WriteLine(jsonDe[&quot;order&quot;][&quot;created_from_client_timezone&quot;].ToString()); // 2023-04-05T14:13:47+0200

var signatureData = JsonConvert.SerializeObject(new Dictionary&lt;string, object&gt;
{
    { &quot;order&quot;, jsonDe[&quot;order&quot;] },
    { &quot;client&quot;, jsonDe[&quot;client&quot;] },
}); // {&quot;order&quot;:{&quot;uuid&quot;:&quot;45B32B3C-B01A-4D82-A03B-D5D9709DC92C&quot;,&quot;created&quot;:&quot;2023-04-05T14:13:47+0200&quot;,&quot;created_from_client_timezone&quot;:&quot;2023-04-05T14:13:47+0200&quot;},&quot;client&quot;:null}

对于System.Text.Json(如果你决定切换)-使用类似的API,例如JsonNode(对我来说可以直接使用,不需要进行日期处理):

var jsonNode = JsonSerializer.Deserialize&lt;JsonNode&gt;(requestBody); // or JsonNode.Parse
Console.WriteLine(jsonNode[&quot;order&quot;][&quot;created_from_client_timezone&quot;].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 = &quot;&quot;&quot;
{
    &quot;current_time&quot;: &quot;2023-04-05T14:13:50+0200&quot;,
    &quot;order&quot;: {
                &quot;uuid&quot;: &quot;45B32B3C-B01A-4D82-A03B-D5D9709DC92C&quot;,
                &quot;created&quot;: &quot;2023-04-05T14:13:47+0200&quot;,
                &quot;created_from_client_timezone&quot;: &quot;2023-04-05T14:13:47+0200&quot;,
           }
}
&quot;&quot;&quot;;
var jsonDe = JsonConvert.DeserializeObject&lt;JToken&gt;(requestBody, new JsonSerializerSettings
{
    DateParseHandling = DateParseHandling.None
});
Console.WriteLine(jsonDe[&quot;current_time&quot;].ToString()); //2023-04-05T14:13:50+0200
Console.WriteLine(jsonDe[&quot;order&quot;][&quot;created_from_client_timezone&quot;].ToString()); // 2023-04-05T14:13:47+0200

var signatureData = JsonConvert.SerializeObject(new Dictionary&lt;string, object&gt;
{
    { &quot;order&quot;, jsonDe[&quot;order&quot;] },
    { &quot;client&quot;, jsonDe[&quot;client&quot;] },
}); // {&quot;order&quot;:{&quot;uuid&quot;:&quot;45B32B3C-B01A-4D82-A03B-D5D9709DC92C&quot;,&quot;created&quot;:&quot;2023-04-05T14:13:47+0200&quot;,&quot;created_from_client_timezone&quot;:&quot;2023-04-05T14:13:47+0200&quot;},&quot;client&quot;: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&lt;JsonNode&gt;(requestBody); // or JsonNode.Parse
Console.WriteLine(jsonNode[&quot;order&quot;][&quot;created_from_client_timezone&quot;].ToString()); // 2023-04-05T14:13:47+0200

P.S.

Be sure that indentation is also handled in the same way on both sides.

huangapple
  • 本文由 发表于 2023年4月6日 20:27:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/75949506.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定