今天早上我的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()
答案 0 :(得分:3)
你和我陷入了同样的陷阱:我们都误读了为代理方法生成的VB.NET代码,因为它返回了一个项目。实际上,它正在返回一个数组。
WSDL使用XML Schema来描述请求和响应的形状。 XML Schema没有“list”的概念,只有序列的概念。默认情况下,当它看到一系列项目时,“添加服务引用”会生成一个数组。您可以通过更改“添加服务引用”或“配置服务引用”对话框的“高级”选项卡上的集合类型来更改此项以生成“列表”。
答案 1 :(得分:1)
以您的方式添加引用时,应将“高级服务引用设置”(“添加服务引用”对话框)中的“集合类型”更改为“system.Collections.Generic.List”。默认情况下,它是“System.Array”。
我不建议使用Add Reference方式,因为你失去了对WCF服务配置的控制,并且VS增加了很多你不需要的垃圾,这会使你的客户/服务链接更难维护
希望这有帮助。
答案 2 :(得分:1)
还有另一种不太知名但功能更强大的机制,用于保留集合类型而无需使用默认集合类型设置。
如果您在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 Forms客户端使用它,这是在WCF管道的两端重用自己的代码的一种非常有效的方法。
一个重要注意事项:要重用您的类,您需要确保检查服务引用配置中的“重用引用程序集中的类型”标志,或者确保reference.svmap中的GenerateInternalTypes标志设置为false(这些是一回事。)