通过 WCF 传递匿名类型的实例

Posted

技术标签:

【中文标题】通过 WCF 传递匿名类型的实例【英文标题】:Passing an instance of anonymous type over WCF 【发布时间】:2011-01-19 09:56:30 【问题描述】:

我有一个 WCF 服务方法,它需要一个对象,然后使用反射检索其属性。

在客户端我创建了一个匿名类型对象

var obj = new FirstName="John", LastName="Doe"

并将其传递给方法。我遇到了一个例外:

Type '<>f__AnonymousType0`2[System.String,System.String]' cannot be serialized. 
Consider marking it with the DataContractAttribute attribute, and marking all 
of its members you want serialized with the DataMemberAttribute attribute.  
See the Microsoft .NET Framework documentation for other supported types.

我不能用序列化属性标记类型或其成员,因为实际上没有明确声明的类型或属性。有没有办法解决这个问题?

【问题讨论】:

【参考方案1】:

你can't use an anonymous type over WCF的answers suggesting错了。

如果您使用默认的DataContractSerializer 在频道上序列化您的类型,那么是的,答案是正确的。这是因为DataContractSerializer支持以下场景:

    使用Serializable attribute 序列化的类型 使用XML Serialization 序列化的类型 使用DataContract attribute 序列化的类型 Plain-Old-C#-Object (POCO) Serialization

由于以下原因,它们分别因匿名类型而失败:

    您不能将属性应用于匿名类型。 XML 序列化需要一个默认的无参数构造函数,而匿名类型则没有。 同 1。 同 2。

然而,您不必强制使用DataContractSerializer 在 WCF 中序列化您的消息。您可以创建一个custom message formatter,您可以使用它自己执行序列化。

如果您作为请求结果发送的类型是匿名类型,则会出现问题。当您返回结果时,它将在命名空间中有一个明确的名称(不是 .NET 意义上的,而是 SOA 意义上的),并且您将不得不处理该具体类型到匿名类型的映射.但是,由于您无法访问实际的匿名类型或在代码中构造它的方式(至少以动态方式),因此您别无选择,只能将其作为对象传递给您,这让它变得毫无价值,因为每个人都必须使用不良做法,例如动态(这本身并不是一个坏做法,但在这种情况下要绕过这些限制,是的),或cast-by-example。

所以最后我会说,虽然可能序列化匿名类型并通过网络发送它们,但所涉及的工作通常不值得。

【讨论】:

+1 表示技术上正确的答案。 -1 用于提及纯邪恶的技术。我担心有人会阅读这篇文章并忽略“不良做法”警告 - 忘记重构,你需要一个驱魔人。 提及任何技术都应该被视为知识共享,而不是被嘲笑。此外,即使是驱魔人也需要了解恶魔。【参考方案2】:

不要这样做。

这是一种聪明的尝试。别。只需声明您需要的数据类型并使用它。如果您需要更松散定义的数据类型,只需使用某种键值映射即可。

您将需要 5 分钟来编写可以永久处理此问题的内容。使用像这样的任何技术都会在未来某个时间点花费您数小时的调试时间。

【讨论】:

是的,我最终传递了一个键对象字典 我遇到了同样的问题,过了半天才发现这是个坏主意。不是我最美好的时光。我只是想用他预言的轶事来支持kyoryu。 但是如果你别无选择,因为你在模仿现有的合同。可以这样做,因为我正在查看执行此操作的现有合同。【参考方案3】:

您可以将对象序列化为 JSON 字符串并通过 WCF 发送,如下所示:

//in WCF Server
dynamic mysentclass = new  FirstName = "John", LastName = "Doe" ;
string jsonstring = JsonConvert.SerializeObject(mysentclass, Newtonsoft.Json.Formatting.Indented);
//send the string through WCF

//in WCF client
dynamic myreceivedclass = JsonConvert.DeserializeObject<dynamic>(jsonstring);
MessageBox.Show(myreceivedclass.FirstName.ToString() + " " + myreceivedclass.LastName.ToString());

示例使用Json.Net,可以在这里获取:

http://www.nuget.org/packages/Newtonsoft.Json/

您也可以使用 System.Web.Script.Serialization.javascriptSerializer(在 System.Web.Extensions.dll 中),它不如 Json.Net 强大,但对于简单的对象就足够了。

【讨论】:

【参考方案4】:

不,没有。虽然有一些技巧和技术可以从方法返回匿名类型的对象,但您不能通过 WCF 发送它们。

WCF 需要知道将要发送的所有具体类型,因为您实际上并不仅仅是调用 .NET 方法。相反,消息调用被转换为序列化消息,因此,通过 WCF 调用传递的任何“事物”必须是可序列化的 - 没有例外。

【讨论】:

【参考方案5】:

你已经得到了答案。做不到。

事实上,您不能将匿名类型的实例从一个方法传递到您的程序中的另一个。您当然不能在 程序之间传递它们。

【讨论】:

实际上,您可以 - 您可以定义“对象”的返回类型,然后只返回匿名类型的实例。它是一种匿名类型,但它最终仍源自“对象”。不推荐,也不打算 - 但有可能 - 至少在 .NET 中 @marc_s:这会编译但几乎没有用,因为不会为System.Object的返回类型生成元数据。 @Aaronaught:我从未说过它在任何方面、形状或形式上都有用 - 只是可能 :-) 我自己永远不会这样做,但在技术上是可行的 @John Saunders:您绝对可以在创建匿名类型的方法之外以强类型的方式使用匿名类型。该机制称为“示例调用”并使用类型推断和事实上,使用与成员相同的布局名称和类型声明的匿名类型实际上 相同的类型(由 C# 规范保证):***.com/questions/2299623/anonymous-types/… - 当然,它是一个 可怕的 实践(根据我的链接答案),但无论 是否 可能,答案是最肯定 是的。 @casperOne:我认为你有责任把这个可怕的想法放在我的脑海里。【参考方案6】:

如前所述,对象必须是可反序列化的,因此您必须事先定义结构。但是,您可以使用继承来定义它们,从而减轻痛苦。 WCF 提供 KnownType 属性以允许服务操作接收基类的对象并将其反序列化为派生类的对象。因此,您仍然只有一个(或几个)可以处理所有场景的服务操作。

【讨论】:

以上是关于通过 WCF 传递匿名类型的实例的主要内容,如果未能解决你的问题,请参考以下文章

30天C#基础巩固-----值类型/引用类型,泛型,空合并操作符(??),匿名方法

GobEncoder 通过 RPC 传递匿名函数

Scala 匿名函数

确定类型是不是为匿名类型

通过禁用匿名身份验证出现 WCF REST 服务问题

php值callback类型和匿名函数(闭包)