簡體   English   中英

接受原始 JSON Asp.net 核心

[英]Accepting raw JSON Asp.net core

我有一個 asp.net 核心方法,我希望它接受 RAW json,我不知道也不會總是知道 json 對象的模式,所以我使用帶點符號的dynamic types

當我將 json 字符串轉義為每個字符時,此方法有效。 我曾嘗試直接使用 json 主體,但這不起作用。 所以看起來我的選擇是Serialize然后Deserialize json。 (非常多余)但如果我嘗試直接使用 JSON 主體,它似乎會以任何其他方式拋出錯誤。

在調試器中,一切似乎都適用於對象/字符串的序列化和反序列化,但是當我嘗試將對象轉換為字符串並給出錯誤時,會在 id(property) 上引發錯誤。 (雖然在調試器中我能夠正確地看到 Id)。

({Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot convert type 'System.Text.Json.JsonElement' to 'string')}

我真的不明白為什么它將類型作為字符串提供但無法轉換它。 我什至嘗試刪除演員表,但仍然收到此錯誤。

public IActionResult Post([FromBody] ExpandoObject requestInput)
{
    try
    {
//Makes a JSON String
        var stringObject = (string) JsonSerializer.Serialize(requestInput);
        DateTime time = DateTime.UtcNow;
// Recreated the Json Object
        dynamic requestObject = JsonSerializer.Deserialize<ExpandoObject>(stringObject); 
// Throws Error here, yet it shows Value as the correct Id number (Value: Type String)
        string reqObject = (string) requestObject.Id;

因此,.NET Core 中尚不支持ExpandoObject MS 說它可能會被添加到 .NET 5.0 中。 在那之前,你可以使用我在一個線程上找到的這個JsonConverter 如果線程消失,我將在此處發布代碼。

你可以這樣使用它:

[HttpPost, Route("testPost")]
public IActionResult TestPost([FromBody] object obj) // just use "object"
{
    // object is: { "hello":"world" }

    var myDynamic = JsonSerializer.Deserialize<dynamic>(
        JsonSerializer.Serialize(obj), new JsonSerializerOptions
        {
            Converters = { new DynamicJsonConverter() }
        });

    var test = (string)myDynamic.hello;
    // test will equal "world"

    return Ok();
}

這是轉換器:

/// <summary>
/// Temp Dynamic Converter
/// by:tchivs@live.cn
/// </summary>
public class DynamicJsonConverter : JsonConverter<dynamic>
{
    public override dynamic Read(ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options)
    {

        if (reader.TokenType == JsonTokenType.True)
        {
            return true;
        }

        if (reader.TokenType == JsonTokenType.False)
        {
            return false;
        }

        if (reader.TokenType == JsonTokenType.Number)
        {
            if (reader.TryGetInt64(out long l))
            {
                return l;
            }

            return reader.GetDouble();
        }

        if (reader.TokenType == JsonTokenType.String)
        {
            if (reader.TryGetDateTime(out DateTime datetime))
            {
                return datetime;
            }

            return reader.GetString();
        }

        if (reader.TokenType == JsonTokenType.StartObject)
        {
            using JsonDocument documentV = JsonDocument.ParseValue(ref reader);
            return ReadObject(documentV.RootElement);
        }
        // Use JsonElement as fallback.
        // Newtonsoft uses JArray or JObject.
        JsonDocument document = JsonDocument.ParseValue(ref reader);
        return document.RootElement.Clone();
    }

    private object ReadObject(JsonElement jsonElement)
    {
        IDictionary<string, object> expandoObject = new ExpandoObject();
        foreach (var obj in jsonElement.EnumerateObject())
        {
            var k = obj.Name;
            var value = ReadValue(obj.Value);
            expandoObject[k] = value;
        }
        return expandoObject;
    }
    private object? ReadValue(JsonElement jsonElement)
    {
        object? result = null;
        switch (jsonElement.ValueKind)
        {
            case JsonValueKind.Object:
                result = ReadObject(jsonElement);
                break;
            case JsonValueKind.Array:
                result = ReadList(jsonElement);
                break;
            case JsonValueKind.String:
                //TODO: Missing Datetime&Bytes Convert
                result = jsonElement.GetString();
                break;
            case JsonValueKind.Number:
                //TODO: more num type
                result = 0;
                if (jsonElement.TryGetInt64(out long l))
                {
                    result = l;
                }
                break;
            case JsonValueKind.True:
                result = true;
                break;
            case JsonValueKind.False:
                result = false;
                break;
            case JsonValueKind.Undefined:
            case JsonValueKind.Null:
                result = null;
                break;
            default:
                throw new ArgumentOutOfRangeException();
        }
        return result;
    }

    private object? ReadList(JsonElement jsonElement)
    {
        IList<object?> list = new List<object?>();
        foreach (var item in jsonElement.EnumerateArray())
        {
            list.Add(ReadValue(item));
        }
        return list.Count == 0 ? null : list;
    }
    public override void Write(Utf8JsonWriter writer,
        object value,
        JsonSerializerOptions options)
    {
        // writer.WriteStringValue(value.ToString());
    }
}

編輯添加:

正如Aluan在評論中指出的那樣,這是使用上面的轉換器處理dynamic的更巧妙的方法。 在您的Startup.cs類中,添加以下內容:

services.AddControllers().AddJsonOptions(options =>
    options.JsonSerializerOptions.Converters.Add(new DynamicJsonConverter()));

然后你不必在你的控制器中做任何愚蠢的事情。 您可以將 body 參數設置為動態,它神奇地工作:

[HttpPost, Route("testPost")]
public IActionResult TestPost([FromBody] dynamic obj)
{
    // object is: { "hello":"world" }

    var test = (string)obj.hello;
    // test will equal "world"

    return Ok();
}

好多了!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM