繁体   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