我有以下代码:
var user = (Dictionary<string, object>)serializer.DeserializeObject(responsecontent);
responsecontent中的输入是JSON,但它没有正确地反序列化为对象。我应该如何正确地反序列化它?
我有以下代码:
var user = (Dictionary<string, object>)serializer.DeserializeObject(responsecontent);
responsecontent中的输入是JSON,但它没有正确地反序列化为对象。我应该如何正确地反序列化它?
当前回答
System.Text.Json
. net core 3.0内置了System.Text.Json,这意味着你可以在不使用第三方库的情况下反序列化/序列化JSON。
Serialize / Deserialize
序列化你的类到JSON字符串:
var json = JsonSerializer.Serialize(model);
将JSON反序列化为强类型类:
var model = JsonSerializer.Deserialize<Model>(json);
解析(。6)净
. net 6引入了System.Text.Json.Nodes命名空间,使DOM能够以类似于Newtonsoft的方式进行解析、导航和操作。Json使用新的类JsonObject, JsonArray, JsonValue和JsonNode。
// JsonObject parse DOM
var jsonObject = JsonNode.Parse(jsonString).AsObject();
// read data from DOM
string name = jsonObject["Name"].ToString();
DateTime date = (DateTime)jsonObject["Date"];
var people = jsonObject["People"].Deserialize<List<Person>>();
类似的方法也适用于JsonArray。这个答案提供了关于JsonObject的更多细节。
需要注意的一点是,System.Text.Json在使用自己的代码时不会自动处理camelCase JSON属性(然而,当使用MVC/WebAPI请求和模型绑定器时,它会自动处理)。
要解决这个问题,你需要传递JsonSerializerOptions作为参数。
JsonSerializerOptions options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // set camelCase
WriteIndented = true // write pretty json
};
// pass options to serializer
var json = JsonSerializer.Serialize(order, options);
// pass options to deserializer
var order = JsonSerializer.Deserialize<Order>(json, options);
System.Text.Json也可用于.Net Framework和.Net Standard,作为一个nuget包System.Text.Json
Edit
在。net 6中,JsonNode.Parse()提供了解析“未知”json的功能
其他回答
string json = @"{
'Name': 'Wide Web',
'Url': 'www.wideweb.com.br'}";
JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
dynamic j = jsonSerializer.Deserialize<dynamic>(json);
string name = j["Name"].ToString();
string url = j["Url"].ToString();
以下来自msdn站点的内容应该有助于为您正在寻找的内容提供一些本地功能。请注意,这是针对Windows 8指定的。下面列出了该站点中的一个这样的示例。
JsonValue jsonValue = JsonValue.Parse("{\"Width\": 800, \"Height\": 600, \"Title\": \"View from 15th Floor\", \"IDs\": [116, 943, 234, 38793]}");
double width = jsonValue.GetObject().GetNamedNumber("Width");
double height = jsonValue.GetObject().GetNamedNumber("Height");
string title = jsonValue.GetObject().GetNamedString("Title");
JsonArray ids = jsonValue.GetObject().GetNamedArray("IDs");
它利用了Windows.Data.JSON命名空间。
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(user)))
{
// Deserialization from JSON
DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(UserListing))
DataContractJsonSerializer(typeof(UserListing));
UserListing response = (UserListing)deserializer.ReadObject(ms);
}
public class UserListing
{
public List<UserList> users { get; set; }
}
public class UserList
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
System.Text.Json
. net core 3.0内置了System.Text.Json,这意味着你可以在不使用第三方库的情况下反序列化/序列化JSON。
Serialize / Deserialize
序列化你的类到JSON字符串:
var json = JsonSerializer.Serialize(model);
将JSON反序列化为强类型类:
var model = JsonSerializer.Deserialize<Model>(json);
解析(。6)净
. net 6引入了System.Text.Json.Nodes命名空间,使DOM能够以类似于Newtonsoft的方式进行解析、导航和操作。Json使用新的类JsonObject, JsonArray, JsonValue和JsonNode。
// JsonObject parse DOM
var jsonObject = JsonNode.Parse(jsonString).AsObject();
// read data from DOM
string name = jsonObject["Name"].ToString();
DateTime date = (DateTime)jsonObject["Date"];
var people = jsonObject["People"].Deserialize<List<Person>>();
类似的方法也适用于JsonArray。这个答案提供了关于JsonObject的更多细节。
需要注意的一点是,System.Text.Json在使用自己的代码时不会自动处理camelCase JSON属性(然而,当使用MVC/WebAPI请求和模型绑定器时,它会自动处理)。
要解决这个问题,你需要传递JsonSerializerOptions作为参数。
JsonSerializerOptions options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase, // set camelCase
WriteIndented = true // write pretty json
};
// pass options to serializer
var json = JsonSerializer.Serialize(order, options);
// pass options to deserializer
var order = JsonSerializer.Deserialize<Order>(json, options);
System.Text.Json也可用于.Net Framework和.Net Standard,作为一个nuget包System.Text.Json
Edit
在。net 6中,JsonNode.Parse()提供了解析“未知”json的功能
我最终创建了一个简单的类,可以动态地创建类型,实例化它们并将它们水合物化,镜像输入JSON的结构。
你可以在这里找到它:
https://github.com/starnutoditopo/JsonToObject
JsonToObjectConverter.cs
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Text.Json;
namespace JsonToObject;
/// <summary>Provides functionalities to convert JSON strings in to CLR objects.</summary>
public class JsonToObjectConverter
{
private class Counter
{
private ulong count;
public Counter()
{
this.count = 0;
}
public ulong Next()
{
this.count++;
return this.count;
}
}
private static ulong assemblyGenerationCounter;
private readonly JsonToObjectConverterOptions options;
static JsonToObjectConverter()
{
assemblyGenerationCounter = 0;
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonToObjectConverter" /> class, using default options.
/// </summary>
/// <param name="options">The options.</param>
public JsonToObjectConverter()
: this(new JsonToObjectConverterOptions())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonToObjectConverter" /> class, using the specified options.
/// </summary>
/// <param name="options">The options.</param>
public JsonToObjectConverter(JsonToObjectConverterOptions options)
{
this.options = options;
}
/// <summary>Converts a JSON string to an instance of a CLR object.</summary>
/// <param name="jsonString">The json string.</param>
/// <returns>
/// <br />
/// </returns>
public object? ConvertToObject(string jsonString)
{
JsonSerializerOptions opt = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = true
};
JsonElement rawResult = JsonSerializer.Deserialize<JsonElement>(jsonString, opt);
object? result = ToStronglyTypedObject(rawResult);
return result;
}
private object? ToStronglyTypedObject(JsonElement? nullableJsonElement)
{
string assemblyNameString;
ulong assemblyId = Interlocked.Increment(ref assemblyGenerationCounter);
try
{
assemblyNameString = string.Format(this.options.RuntimeGeneratedAssemblyNameTemplate, assemblyId.ToString(CultureInfo.InvariantCulture));
}
catch
{
throw new InvalidOperationException($@"Unable to generate assembly name using template '{this.options.RuntimeGeneratedAssemblyNameTemplate}' and id '{assemblyId}'. Please, review the {nameof(JsonToObjectConverterOptions.RuntimeGeneratedAssemblyNameTemplate)} property in the options.");
}
ModuleBuilder moduleBuilder = CreateModuleBuilder(assemblyNameString, this.options.RuntimeGeneratedModuleName);
Counter typeGenerationCounter = new Counter();
var result = ToStronglyTypedObject(nullableJsonElement, moduleBuilder, typeGenerationCounter);
return result;
}
private object? ToStronglyTypedObject(
JsonElement? nullableJsonElement,
ModuleBuilder moduleBuilder,
Counter typeGenerationCounter
)
{
if (nullableJsonElement == null)
{
return null;
}
JsonElement jsonElement = nullableJsonElement.Value;
switch (jsonElement.ValueKind)
{
case JsonValueKind.Undefined:
return null;
case JsonValueKind.String:
return jsonElement.GetString();
case JsonValueKind.False:
return false;
case JsonValueKind.True:
return true;
case JsonValueKind.Null:
return null;
case JsonValueKind.Number:
{
if (jsonElement.TryGetDouble(out var result))
{
return result;
}
}
throw new InvalidOperationException($"Unable to parse {jsonElement} as number.");
case JsonValueKind.Object:
{
ulong typeId = typeGenerationCounter.Next();
string typeName;
try
{
typeName = string.Format(this.options.RuntimeGeneratedTypeNameTemplate, typeId.ToString(CultureInfo.InvariantCulture));
}
catch
{
throw new InvalidOperationException($@"Unable to generate type name using template '{this.options.RuntimeGeneratedTypeNameTemplate}' and id '{typeId}'. Please, review the {nameof(JsonToObjectConverterOptions.RuntimeGeneratedTypeNameTemplate)} property in the options.");
}
TypeBuilder typeBuilder = CreateTypeBuilder(moduleBuilder, typeName);
Dictionary<string, object?> propertyValues = new Dictionary<string, object?>();
foreach (var property in jsonElement.EnumerateObject())
{
string propertyName = property.Name;
object? propertyValue = ToStronglyTypedObject(property.Value, moduleBuilder, typeGenerationCounter);
Type propertyValueType;
if (null == propertyValue)
{
propertyValueType = typeof(object);
}
else
{
propertyValueType = propertyValue.GetType();
}
CreateAutoImplementedProperty(typeBuilder, propertyName, propertyValueType);
propertyValues.Add(propertyName, propertyValue);
}
Type resultType = typeBuilder.CreateType()!;
object result = Activator.CreateInstance(resultType)!;
foreach (var pair in propertyValues)
{
var propertyInfo = resultType.GetProperty(pair.Key)!;
propertyInfo.SetValue(result, pair.Value);
}
return result;
}
case JsonValueKind.Array:
{
List<object?> list = new List<object?>();
foreach (var item in jsonElement.EnumerateArray())
{
object? value = ToStronglyTypedObject(item, moduleBuilder, typeGenerationCounter);
list.Add(value);
}
return list.ToArray();
}
default:
throw new InvalidOperationException($"Value type '{jsonElement.ValueKind}' is not supported");
}
}
private static ModuleBuilder CreateModuleBuilder(
string assemblyNameString,
string moduleName
)
{
// create assembly name
var assemblyName = new AssemblyName(assemblyNameString);
// create the assembly builder
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
// create the module builder
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName);
return moduleBuilder;
}
private static TypeBuilder CreateTypeBuilder(
ModuleBuilder moduleBuilder,
string typeName
)
{
// create the type builder
TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
return typeBuilder;
}
private static void CreateAutoImplementedProperty(
TypeBuilder builder,
string propertyName,
Type propertyType
)
{
const string PrivateFieldPrefix = "m_";
const string GetterPrefix = "get_";
const string SetterPrefix = "set_";
// Generate the field.
FieldBuilder fieldBuilder = builder.DefineField(
string.Concat(PrivateFieldPrefix, propertyName),
propertyType, FieldAttributes.Private);
// Generate the property
PropertyBuilder propertyBuilder = builder.DefineProperty(
propertyName, PropertyAttributes.HasDefault, propertyType, null);
// Property getter and setter attributes.
MethodAttributes propertyMethodAttributes =
MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.HideBySig;
// Define the getter method.
MethodBuilder getterMethod = builder.DefineMethod(
string.Concat(GetterPrefix, propertyName),
propertyMethodAttributes, propertyType, Type.EmptyTypes);
// Emit the IL code.
// ldarg.0
// ldfld,_field
// ret
ILGenerator getterILCode = getterMethod.GetILGenerator();
getterILCode.Emit(OpCodes.Ldarg_0);
getterILCode.Emit(OpCodes.Ldfld, fieldBuilder);
getterILCode.Emit(OpCodes.Ret);
// Define the setter method.
MethodBuilder setterMethod = builder.DefineMethod(
string.Concat(SetterPrefix, propertyName),
propertyMethodAttributes, null, new Type[] { propertyType });
// Emit the IL code.
// ldarg.0
// ldarg.1
// stfld,_field
// ret
ILGenerator setterILCode = setterMethod.GetILGenerator();
setterILCode.Emit(OpCodes.Ldarg_0);
setterILCode.Emit(OpCodes.Ldarg_1);
setterILCode.Emit(OpCodes.Stfld, fieldBuilder);
setterILCode.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getterMethod);
propertyBuilder.SetSetMethod(setterMethod);
}
}
JsonToObjectConverterOptions.cs
namespace JsonToObject;
/// <summary>
/// Defines the options to instantiate a <see cref="JsonToObjectConverter" /> object.
/// </summary>
public class JsonToObjectConverterOptions
{
private const string CONSTANTS_RuntimeGeneratedModuleName = $"RuntimeGeneratedModule";
private const string CONSTANTS_RuntimeGeneratedAssemblyNameTemplate = "RuntimeGeneratedAssembly_{0}";
private const string CONSTANTS_RuntimeGeneratedTypeNameTemplate = "RuntimeGeneratedType_{0}";
/// <summary>Gets or sets the name of the runtime-generated module.</summary>
/// <value>The name of the runtime-generated module.</value>
public string RuntimeGeneratedModuleName { get; set; } = CONSTANTS_RuntimeGeneratedModuleName;
/// <summary>Gets or sets the template to use to generate the name of runtime-generated assemblies.</summary>
/// <value>The template to use to generate the name of runtime-generated assemblies.</value>
/// <remarks>Should contain a "{0}" placeholder.</remarks>
public string RuntimeGeneratedAssemblyNameTemplate { get; set; } = CONSTANTS_RuntimeGeneratedAssemblyNameTemplate;
/// <summary>Gets or sets the template to use to generate the name of runtime-generated types.</summary>
/// <value>The template to use to generate the name of runtime-generated types.</value>
/// <remarks>Should contain a "{0}" placeholder.</remarks>
public string RuntimeGeneratedTypeNameTemplate { get; set; } = CONSTANTS_RuntimeGeneratedTypeNameTemplate;
}