如何从Web api JSON响应中派生出C#动态对象?

Pro*_*ofK 4 c# serialization json dynamic json.net

大多数情况下,默认情况下,我们没有使用我们选择的静态语言定义类,这使得白色成为如何反序列化例如从调用public和open wen api返回的JSON的窘境,致力于没有单一的语言,除了HTML和JSON的"语言".

在.NET中,现在几乎所有api查询都已完成HttpClient,类似于下面的Google Books API ISBN查询:

public class GoogleBooksClient
{
    private const string IsbnUrl = "books/v1/volumes?q=isbn:{0}";
    private static HttpClient _client = new HttpClient();
    ...
    public async Task<object> GetDetailsByIsbn(string isbn)
    {
        var json = await _client.GetStringAsync(string.Format(IsbnUrl, isbn));
        dynamic objX = JsonConvert.DeserializeObject(json);
        return objX;
    }
}
Run Code Online (Sandbox Code Playgroud)

这里最大的问题是,无论objX是声明var',object还是,或者dynamic,JObjectDeserializeObject没有已知类型的情况下调用时,它始终是对大而丑的实例的引用.在这种情况下,返回的JSON对象非常复杂,并且有龙等待那些努力编写可以解析所述JSON的C#类的人.

这是使用C#dynamic对象的理想且有意的机会,其中当解析JSON时,可以递归地将属性(并且很少用于API响应的函数)添加到所述动态对象.

相反,NewtonSoft.JSON将JSON持有的数据与非常不透明的Jobject数据结构的繁重的繁文缛节绑定紧密绑定在一起.到目前为止,我感到惊讶和失望,NewtonSoft不能简单地提取一个纯粹的动态对象,没有他们JObject迷宫的所有混淆官僚作风.

有没有其他方法可以简单地将JSON解析为C#动态对象,就像在其他场景中将其解析为显式动态JavaScript对象一样?

增加:通过" 混淆他们的JObject迷宫的官僚主义 ",我的意思是以下代码:

var json = JsonConvert.SerializeObject(new Person {Id = 196912135012878, Age = 47, Name = "Brady"});
var jObj = JsonConvert.DeserializeObject(json);
Run Code Online (Sandbox Code Playgroud)

生成JObject我的调试器显示为的实例:

JObject属性的调试器视图

对我来说,这看起来更像是在解析JSON时应该在内部使用的东西,而不是解析的最终产品,它应该只是从该JSON解析的属性的纯粹表示.理想情况下,这将是一个C#动态对象,没有任何属性供任何解析器使用.

dbc*_*dbc 8

而不是a JObject,你可以反序列化为一个ExpandoObject由Json.NET的内置转换器支持的ExpandoObjectConverter.如果是数组,则可以反序列化为a List<ExpandoObject>然后选择a List<dynamic>.如果是原始值,则可以返回JValue.Value.

例如,如果您事先知道您的JSON代表一个对象,那么就这样做:

dynamic dyn = JsonConvert.DeserializeObject<ExpandoObject>(json);
Run Code Online (Sandbox Code Playgroud)

如果您事先不知道根JSON容器的内容,可以将其作为a加载JToken并使用以下扩展方法:

public static class JsonExtensions
{
    public static dynamic ToDynamic(this JToken token)
    {
        if (token == null)
            return null;
        else if (token is JObject)
            return token.ToObject<ExpandoObject>();
        else if (token is JArray)
            return token.ToObject<List<ExpandoObject>>().Cast<dynamic>().ToList();
        else if (token is JValue)
            return ((JValue)token).Value;
        else
            // JConstructor, JRaw
            throw new JsonSerializationException(string.Format("Token type not implemented: {0}", token));
    }
}
Run Code Online (Sandbox Code Playgroud)

然后做:

dynamic dyn = JsonConvert.DeserializeObject<JToken>(json).ToDynamic();
Run Code Online (Sandbox Code Playgroud)

样品小提琴.