在 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)中的任何一种都可以吗?我该怎么做?
【问题讨论】:
您应该重新表述您的问题:就像现在一样,答案是 Yes 和 Yes。但我想这对你帮助不大。 您可以尝试将返回的内容分配给 dynamic 变量并从中访问属性/值 - 但您需要事先知道属性的名称是什么跨度> 当然,我已经知道数据结构了。我只是不想在它上面建立一个模型。 您是否考虑过在 .NET 中使用XPath
选择器?这些与LINQ
和XDocument
类一起提供了一种非常简单而强大的访问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<T>()
扩展方法,您需要使用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
,这在 dynamic
和 XML
之间转换时可能非常有用。
特别是关于 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<ExpandoObject>().Result
将 HttpContent
检索为 dynamic
?
是的,我使用它并等待结果就地读取结果,这会阻塞线程直到结果完成,但您可以使用太延续。但重要的是,这样做,将其读取为 ExpandoObject,然后您可以将其读取为动态的,按照您的意图进行以上是关于在 C# 中从 Web 检索匿名类型的主要内容,如果未能解决你的问题,请参考以下文章