c# - 接受原始 JSON Asp.net 核心
问题描述
我有一个 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;
解决方案
因此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();
}
这是转换器:
/// <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();
}
好多了!
推荐阅读
- javascript - Javascript无法遍历数组
- vb.net - 有没有一种简单的方法可以将字符串洗牌到数组中?
- php - Wordpress:一个 WP_Query / 多个帖子类型 / 每种帖子类型的最大数量
- xaml - 关注完成事件的 ListView 中的下一个条目
- java - 如何从 Spring WebClient POST 调用中引发异常?
- javascript - URL.createObjectURL 带有“.gif”文件扩展名
- python - 删除嵌套 for 循环作为 python 中的附加函数
- flutter - 在 Flutter 中导航到另一个页面
- pyspark - 将小 PySpark DataFrame 写入镶木地板时出现内存错误
- javascript - 通过 id 获取输入值