解决一个通过 WebReference 调用 WCF 时自定义 DataContract 类参数提交的问题

先看一下VS2013自动创建默认的IService1.vb,注意自定义的数据契约 CompositeType

' 注意: 使用上下文菜单上的“重命名”命令可以同时更改代码和配置文件中的接口名“IService1”。
<ServiceContract()>
Public Interface IService1

    <OperationContract()>
    Function GetData(ByVal value As Integer) As String

    <OperationContract()>
    Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType

    ' TODO: 在此添加您的服务操作

End Interface

' 使用下面示例中说明的数据约定将复合类型添加到服务操作。

<DataContract()>
Public Class CompositeType

    <DataMember()>
    Public Property BoolValue() As Boolean

    <DataMember()>
    Public Property StringValue() As String

End Class

通过添加 WebReference 引用后的客户端代码

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim wrClient As New localhost.Service1
    Dim data As New localhost.CompositeType
    data.BoolValue = True
    'data.BoolValueSpecified = True
    data.StringValue = "Hello world"

    Dim result As localhost.CompositeType = wrClient.GetDataUsingDataContract(data)
    MessageBox.Show(result.StringValue)
End Sub

注意被注释掉的那一行,在没有显式地指定 data.BoolValueSpecified = True 的情况下,BoolValue 的值不会被客户端提交到服务端,服务端接收到的 data 参数中BoolValue 将赋值为其默认值(false)。

类似的还有服务契约中的参数如果不是String类型,则必须指定 [参数名]Specified = True,该参数才会被执行提交,如

  <OperationContract()>
   Function GetDataUsingBoolValue(ByVal boolValue As Boolean, ByVal StringValue As String) As String

对应的客户端调用代码

MessageBox.Show(wrClient.GetDataUsingBoolean(True, True, "Hello World"))

如果你打算客户端省点功夫,不想总是显式地设置 Specified = True, 那么在声明服务契约和数据契约时,就要多做一点工作

<ServiceContract()>
Public Interface IService1

    <OperationContract()>
    Function GetData(ByVal value As Integer) As String

    <OperationContract()>
    Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType

    ' TODO: 在此添加您的服务操作

    ''' <summary>
    ''' 存在非String类参数的方法
    ''' </summary>
    ''' <param name="boolValue"></param>
    ''' <param name="StringValue"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' 注意:DataContractFormat(Style:=OperationFormatStyle.Rpc)
    ''' 如果没有设置此属性,非String类的参数默认不会被提交,是否被提交将由 [非String类参数名]Specified 的取值决定
    ''' </remarks>
    <OperationContract(), DataContractFormat(Style:=OperationFormatStyle.Rpc)>
    Function GetDataUsingBoolValue(ByVal boolValue As Boolean, ByVal StringValue As String) As String
End Interface

' 使用下面示例中说明的数据约定将复合类型添加到服务操作。

<DataContract()>
Public Class CompositeType

    ''' <summary>
    ''' 非String类的参数
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks>
    ''' 注意:IsRequired:=True
    ''' 如果没有设置此属性,该参数默认不会被提交,是否被提交将由 BoolValueSpecified 的取值决定
    ''' </remarks>
    <DataMember(IsRequired:=True)>
    Public Property BoolValue() As Boolean

    <DataMember()>
    Public Property StringValue() As String

End Class

具体的解释,可以参见这里

今天为这个问题折腾了老半天,尤其是 DataContract 里面的 DataMember(IsRequired:=True) 藏得比较深,特别是在客户端通过 ServiceReference 引用的时候没有这个问题,到了用 WebReference 引用的时候,发现非String类型(如 Integer, Double, Single, DateTime等,不过 Byte数组除外)的参数死活提交不上去了。

立此存照,希望能帮到不小心掉进这个坑里的同行,:)

posted @ 2017-02-24 00:51  树欲静·而风不止  阅读(461)  评论(0编辑  收藏  举报