在 C# 中从 Web 检索匿名类型

Posted

技术标签:

【中文标题】在 C# 中从 Web 检索匿名类型【英文标题】:Retrieve anonymous type from the web in C# 【发布时间】:2013-08-02 01:03:26 【问题描述】:

我正在尝试从网络上检索一些数据。数据以 JSON 对象或 XML 的形式提供:在这两种情况下,我都希望 不基于此 XML/JSON 的结构构建模型,而只是检索我需要的数据。

HttpResponseMessage response = await client.PostAsync(
"http://www.someAPI.com/api.xml",
requestContent);

response.EnsureSuccessStatusCode();

HttpContent content = response.Content;

如果我必须基于我将收到的数据结构构建模型,我会这样做:我只想知道是否有任何替代方案。我可以将content 解析为匿名类型,例如,将数据检索为任意字段或属性或数组索引吗?

假设:response.Countries[5].CountryId。这两种类型(JSON 和 XML)中的任何一种都可以吗?我该怎么做?

【问题讨论】:

您应该重新表述您的问题:就像现在一样,答案是 YesYes。但我想这对你帮助不大。 您可以尝试将返回的内容分配给 dynamic 变量并从中访问属性/值 - 但您需要事先知道属性的名称是什么跨度> 当然,我已经知道数据结构了。我只是不想在它上面建立一个模型。 您是否考虑过在 .NET 中使用 XPath 选择器?这些与LINQXDocument 类一起提供了一种非常简单而强大的访问XML 数据的方法。 一个模型,必须创建一个POCO 才能访问内容?那么dynamic 可能是解决这个问题的好方法。 【参考方案1】:

编辑 #2:

我在下面添加了一条关于使用出色的 Json.NET 库反序列化为 dynamic 对象的注释。


编辑#1:

感谢Hoghweed's answer,我下面的回答现在更完整了。具体来说,我们需要cast将我们从HttpResponseMessage.Content 获得的HttpContent 转换为ExpandoObject,以便dynamic-ness 按预期工作:

dynamic content = response.Content.ReadAsAsync<ExpandoObject>().Result;
var myPropertyValue = content.MyProperty;

要获得ReadAsync&lt;T&gt;() 扩展方法,您需要使用NuGet 从Microsoft.AspNet.WebApi.Client 包(here's the "old" Nuget page,其中提到它现在包含在上面包)。


原答案:

因此,您不必创建POCO 并且必须在返回的 XML/JSON 结构发生变化时管理其属性。 dynamic 似乎非常适合您的用例:

HttpResponseMessage response = await client.PostAsync(
"http://www.someAPI.com/api.xml", requestContent);

response.EnsureSuccessStatusCode();

dynamic content = response.Content.ReadAsAsync<ExpandoObject>().Result; // Notice the use of the dynamic keyword
var myPropertyValue = content.MyProperty; // Compiles just fine, retrieves the value of this at runtime (as long as it exists, of course)

特别是关于 XML:您可以尝试 Anoop Madhusudanan's ElasticObject,这在 dynamicXML 之间转换时可能非常有用。

特别是关于 JSON:您可以使用 Json.NET 执行以下操作:

dynamic content = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result);
var myPropertyValue = content.MyProperty;

好处是您不会依赖于 Microsoft.AspNet.WebApi.Client 包(从 v4.0.30506.0 开始,它依赖于 Json.NET)。缺点是您不能将它用于 XML。

希望这会有所帮助。

【讨论】:

ExpandoObject 似乎是 .NET 4.0 对 ElasticObject 之类的官方回答。 是的——但ElasticObject 正在积极开发中,而ExpandoObject 更新与.NET 框架的新版本相关联(不过,looks to be changing)。这还取决于是否允许 OP 使用第三方软件。 非常感谢您的帮助。我的代码现在无法编译有一些大问题,但我会尽快测试您发布的解决方案并标记您的答案。 @SameerSingh 确实——在亲身体验过获得第三方库的批准是多么棘手之后,我尝试找到尽可能使用官方资料的解决方案。不过我之前没见过ElasticObject……它看起来很棒;我可能得试试看。 它根本不工作。 “System.Net.Http.StreamContent”不包含“MyProperty”的定义【参考方案2】:

HttpResponseMessage.Content 读取为动态是可能的,但访问它是动态的,而是使用适当的扩展方法将其内容读取为ExpandoObject

我为此写了一个行为测试,很明显是一个测试,但上下文与您的问题相似:

    一个带有 json 内容的 响应对象(我在测试中使用了 json) 没有模型对象的动态分辨率

测试结构如下:

    给定一个匿名对象 使用 JsonMedia 格式化程序创建包含此对象内容的 HttpResponseMessage 时 然后可以使用ExpandoObject 以动态方式访问它

测试前提是安装Microsoft.AspNet.WebApi.Client 所以,这是测试的代码

public class RetrieveAnonymousTypeFromTheWebInCSharp 
    : BehaviorTest

    private object _testModel;
    private HttpResponseMessage _message;

    protected override void Given()
    
        _testModel = new
            
                Id = 14,
                MyProperty = "Test property value"
            ;
    

    protected override void When()
    
        _message = new HttpResponseMessage(HttpStatusCode.Accepted)
                       
                           Content =
                               new ObjectContent(_testModel.GetType(),
                                                 _testModel,
                                                 new JsonMediaTypeFormatter
                                                     ())
                       ;
    

    [Test]
    public void Then()
    
        //then properties could be retrieved back by dynamics
        dynamic content = _message.Content.ReadAsAsync<ExpandoObject>().Result;
        var propertyvalue = content.MyProperty;
        Assert.That(propertyvalue, Is.Not.Null.And.EqualTo("Test property value"));
    

xml 也可以这样做。

【讨论】:

有趣 - 所以只需要 .ReadAsAsync&lt;ExpandoObject&gt;().ResultHttpContent 检索为 dynamic? 是的,我使用它并等待结果就地读取结果,这会阻塞线程直到结果完成,但您可以使用太延续。但重要的是,这样做,将其读取为 ExpandoObject,然后您可以将其读取为动态的,按照您的意图进行

以上是关于在 C# 中从 Web 检索匿名类型的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中返回匿名类型

C#中的匿名类型

C#编程(十六)----------匿名类型

如何在 C# 中从 Npgsql 4.1.5.0 执行匿名块 PL/pgSQL (PostgreSQL 13)

go与C#的匿名类型判断比较

在 C# 中将匿名类型转换为键/值数组?