我有以下代码:

var user = (Dictionary<string, object>)serializer.DeserializeObject(responsecontent);

responsecontent中的输入是JSON,但它没有正确地反序列化为对象。我应该如何正确地反序列化它?


当前回答

您可以使用以下扩展

public static class JsonExtensions
{
    public static T ToObject<T>(this string jsonText)
    {
        return JsonConvert.DeserializeObject<T>(jsonText);
    }

    public static string ToJson<T>(this T obj)
    {
        return JsonConvert.SerializeObject(obj);
    } 
}

其他回答

下面是一个使用csc v2.0.0.61501的完整的可运行示例。

包:

nuget install Microsoft.AspNet.WebApi.Core
nuget install Microsoft.Net.Http
nuget install Newtonsoft.Json

代码:

using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;

public static class App
{
    static void Main()
    {
        MainAsync().GetAwaiter().GetResult();
    }

    static async Task MainAsync()
    {
        string url = "https://httpbin.org/get";
        var client = new HttpClient();

        // The verbose way:
        //HttpResponseMessage response = await client.GetAsync(url);
        //response.EnsureSuccessStatusCode();
        //string responseBody = await response.Content.ReadAsStringAsync();

        // Or:
        string responseBody = await client.GetStringAsync(url);

        var obj = JsonConvert.DeserializeObject<dynamic>(responseBody);
        Console.WriteLine(obj);
        Console.WriteLine(obj.headers.Host);
    }
}

编译器命令:

 csc http_request2.cs -r:".\Microsoft.AspNet.WebApi.Core.5.2.9\lib\net45\System.Web.Http.dll" -r:".\Microsoft.Net.Http.2.2.29\lib\net40\System.Net.Http.dll" -r:".\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll"

输出:

{
  "args": {},
  "headers": {
    "Host": "httpbin.org",
    "X-Amzn-Trace-Id": "Root=1-633dce52-64f923bb42c99bf46f78672c"
  },
  "origin": "98.51.7.199",
  "url": "https://httpbin.org/get"
}
httpbin.org

无法加载Newtonsoft.json文件或程序集。系统无法找到指定的文件,我不得不将Newtonsoft.Json.dll移到已编译的二进制文件旁边。

另一个本地解决方案是JavaScriptSerializer,它不需要任何第三方库,只需要对System.Web.Extensions的引用。这不是一个新功能,而是一个自3.5以来非常不为人知的内置功能。

using System.Web.Script.Serialization;

..

JavaScriptSerializer serializer = new JavaScriptSerializer();
objectString = serializer.Serialize(new MyObject());

和背部

MyObject o = serializer.Deserialize<MyObject>(objectString)

这里有一些不使用第三方库的选项:

// For that you will need to add reference to System.Runtime.Serialization
var jsonReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(@"{ ""Name"": ""Jon Smith"", ""Address"": { ""City"": ""New York"", ""State"": ""NY"" }, ""Age"": 42 }"), new System.Xml.XmlDictionaryReaderQuotas());

// For that you will need to add reference to System.Xml and System.Xml.Linq
var root = XElement.Load(jsonReader);
Console.WriteLine(root.XPathSelectElement("//Name").Value);
Console.WriteLine(root.XPathSelectElement("//Address/State").Value);

// For that you will need to add reference to System.Web.Helpers
dynamic json = System.Web.Helpers.Json.Decode(@"{ ""Name"": ""Jon Smith"", ""Address"": { ""City"": ""New York"", ""State"": ""NY"" }, ""Age"": 42 }");
Console.WriteLine(json.Name);
Console.WriteLine(json.Address.State);

有关System.Web.Helpers.Json的更多信息,请参阅链接。

更新:现在最简单的上网方式。helper是使用NuGet包的。


如果你不关心早期的windows版本,你可以使用windows . data . json命名空间的类:

// minimum supported version: Win 8
JsonObject root = Windows.Data.Json.JsonValue.Parse(jsonString).GetObject();
Console.WriteLine(root["Name"].GetString());
Console.WriteLine(root["Address"].GetObject()["State"].GetString());

以下来自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命名空间。

我最终创建了一个简单的类,可以动态地创建类型,实例化它们并将它们水合物化,镜像输入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;
}