接受原始 JSON Asp.net core

PHP*_*oob 0 .net c# asp.net .net-core asp.net-core

我有一个 asp.net core 方法,我希望它接受 RAW json,我不知道也不会总是知道 json 对象的架构,所以我使用dynamic types点表示法。

当我将 json 转义为每个字符时,此方法有效。我尝试过直接使用 json body,但这不起作用。所以看来我的选择是Serialize然后Deserialize是 json. (非常多余)但如果我尝试直接使用 JSON 主体,它似乎会以任何其他方式抛出错误。

在调试器中,一切似乎都适用于对象/字符串的序列化和反序列化,但当我尝试将对象转换为字符串并给出错误时,会在 id(属性)上引发错误。(尽管在调试器中我能够正确地看到 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;
Run Code Online (Sandbox Code Playgroud)

And*_*ndy 5

ExpandoObject因此.NET Core尚不支持。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();
}
Run Code Online (Sandbox Code Playgroud)

这是转换器:

/// <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());
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑添加:

正如Aluan在评论中dynamic指出的那样,这是一种更灵活的方法来处理使用上面的转换器。在您的班级中添加以下内容:Startup.cs

services.AddControllers().AddJsonOptions(options =>
    options.JsonSerializerOptions.Converters.Add(new DynamicJsonConverter()));
Run Code Online (Sandbox Code Playgroud)

那么你就不必在控制器中做任何愚蠢的事情了。您只需将 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();
}
Run Code Online (Sandbox Code Playgroud)

好多了!

  • 如果您在调用“AddJsonOptions”时添加此转换器,我相信您可以使参数“dynamic”。 (2认同)