【问题标题】:wcf reference not being generated correctlywcf 引用未正确生成
【发布时间】:2011-10-28 14:54:43
【问题描述】:

今天早上我的 WCF 引用遇到了一个奇怪的问题。简而言之,我设置了一个双工服务,以便服务器可以通过发送数据契约中的对象来通知客户端。当客户端连接时,它会在服务器上运行一个函数以根据服务类的共享队列中的内容返回List(Of NewItem)。问题是,当我在客户端更新我的服务引用时,它说函数返回一个NewItem 对象,而不是List(Of NewItem) 对象。我可以进入参考并手动将其更改为List 对象,它会很好地传输。任何想法为什么服务引用生成器会任意更改我的返回类型?

以下是相关代码:

<ServiceContract(
    CallbackContract:=GetType(INotifyCallback),
    SessionMode:=ServiceModel.SessionMode.Required)>
Public Interface INotifyService
    <OperationContract()>
    Function GetNewServerItems() As List(Of NewItem)
End Interface

<DataContract>
<Serializable>
Public Class NewItem
    <DataMember()>
    Public Property ItemNum As String

    <DataMember()>
    Public Property Timestamp As DateTime
End Class

<ServiceBehavior(
    ConcurrencyMode:=ServiceModel.ConcurrencyMode.Single,
    InstanceContextMode:=ServiceModel.InstanceContextMode.Single)>
Public Class NotifyService
    Implements INotifyService

    Shared _server_items As New List(Of NewItem)

    Public Function GetNewServerItems() As List(Of NewItem)
        Return _server_items
    End Function
End Class

在 Reference.vb 中(简体):

<System.ServiceModel.OperationContractAttribute(Action:="http://tempuri.org/INotifyService/GetNewServerItems", ReplyAction:="http://tempuri.org/INotifyService/GetNewServerItemsResponse")>  _
Function GetNewServerItems() As NotifyGateway.NewItem()

【问题讨论】:

  • 您是否通过右键单击项目并选择“添加服务引用”来添加引用?
  • 你是不是不小心离开了&lt;ServiceContract&gt;
  • @JohnSaunders - 并非偶然。我把它们排除在外是因为这是一份很长的合同,我只想包括最基本的内容。我已经把它们添加进去了。
  • 对您的原始帖子的一个轻微但重要的澄清:该函数返回一个 NewItem 对象数组,而不是单个 NewItem 对象。您可以轻松地在接收端创建一个 List(Of NewItem) 并从数组中加载它,或者如果更改默认集合类型会导致其他副作用,则直接使用数组。

标签: vb.net wcf


【解决方案1】:

你和我都落入了同一个陷阱:我们都误认为为代理方法生成的 VB.NET 代码返回了单个项目。其实就是返回一个数组。

WSDL 使用 XML Schema 来描述请求和响应的形式。 XML Schema 没有“列表”的概念,只有序列的概念。默认情况下,当它看到一系列项目时,“添加服务引用”会生成一个数组。您可以更改它以生成“列表”,只需更改“添加服务引用”或“配置服务引用”对话框的“高级”选项卡上的集合类型。

【讨论】:

  • ...你是对的。 NewItemNewItem() 不同。应该注意到这一点。
【解决方案2】:

以您的方式添加引用时,您应该将高级服务引用设置(添加服务引用对话框)中的“集合类型”更改为“system.Collections.Generic.List”。默认为“System.Array”。

我不推荐尽管使用添加引用方式,因为您无法控制 WCF 服务的配置,并且 VS 添加了很多您不需要的垃圾,这会使您的客户端/服务链接更难维护.

希望这会有所帮助。

【讨论】:

  • -1:请不要在没有更多证据的情况下提出此类建议。此外,并非不询问他使用的是哪个 .NET 版本,因为 .NET 4.0 通过省略默认值来生成更小的配置文件。
  • 答案的第一部分似乎解决了眼前的问题。关于答案的第二部分:如果不使用“添加服务引用”方法,我将如何添加服务引用或以其他方式让我的合同生效? (是的,我使用的是 .NET 4。)
  • 对,对不起。我不是指配置文件,我的意思是当使用“添加服务引用”时,结果非常冗长,难以管理和维护,配置更改可能会被覆盖,而不是重用您的界面,它会生成一个副本。所以恕我直言,手动配置 WCF(手动或使用适当的工具)是最好的方法,我之前应该这样说。希望这能让我的回答更清楚,再次抱歉。
【解决方案3】:

还有另一种鲜为人知但更强大的机制来保留集合类型,而无需使用默认集合类型设置。

如果您在 WCF 管道两侧的代码中使用了 CollectionDataContract 类,则此机制特别有用。

解决方案涉及编辑作为 WCF 服务引用的一部分生成的 svcmap,并为要序列化的每个集合类型添加特定的 CollectionMapping 条目。这里要注意的主要事情是泛型:如果 WCF 发现给定类的多个匹配项,它将拒绝生成代码。

实际进行更改:

1) 显示项目中包含您的 WCF 服务引用的所有文件。

2) 扩展您的服务参考

3) 双击 Reference.svmap 文件进行编辑。

4) 在 CollectionMappings 部分添加您的条目​​(如果它不存在,您可以添加它)。

例如,为了传输通用字典和列表,以及传输 StringCollections,您可以有以下条目:

<CollectionMappings>
  <CollectionMapping TypeName="System.Collections.Generic.Dictionary`2" Category="Dictionary" />
  <CollectionMapping TypeName="System.Collections.Generic.List`1" Category="List" />
  <CollectionMapping TypeName="System.Collections.Specialized.StringCollection" Category="List" />
<CollectionMappings>

类别为 Dictionary 的第一项将用作默认的 Dictionary 集合类型,类别为 List 的第一项将用作默认的 Collection 类型。

我们有超过 200 个集合类,我们以这种方式用于 Silverlight 和 Windows 窗体客户端,这是在 WCF 管道的两端重用您自己的代码的一种极其有效的方式。

一个重要的注意事项:要重用您的类,您需要确保选中服务引用配置中的“重用引用程序集中的类型”标志,或者将 reference.svmap 中的 GenerateInternalTypes 标志设置为 false(这些是一样的东西)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多