2

我正在编写一个 WCF WebMethod 来将文件上传到,其中我从网络上获取了片段。WCF 界面如下所示:

<ServiceContract()>
Public Interface ITransferService

    <OperationContract()>
    Sub UploadFile(ByVal request As RemoteFileInfo)

End Interface

<MessageContract()>
Public Class RemoteFileInfo
    Implements IDisposable

    <MessageHeader(MustUnderstand:=True)>
    Public FileName As String

    <MessageHeader(MustUnderstand:=True)>
    Public Length As Long

    <MessageBodyMember(Order:=1)>
    Public FileByteStream As System.IO.Stream

    Public Sub Dispose() Implements IDisposable.Dispose
        If FileByteStream IsNot Nothing Then
            FileByteStream.Close()
            FileByteStream = Nothing
        End If
    End Sub

End Class

在 ASP.NET 中,当使用 web 方法时,由于某种原因,它仅在将接口用作实例化的一部分时才有效RemoteFileInfo

Protected Sub btn_Click(sender As Object, e As EventArgs) Handles btn.Click
    If fu.HasFile Then
        Dim fi As New System.IO.FileInfo(fu.PostedFile.FileName)

        ' this is the line in question --------------
        Dim cu As ServiceReference1.ITransferService = New ServiceReference1.TransferServiceClient()
        ' -------------------------------------------

        Dim uri As New ServiceReference1.RemoteFileInfo()
        Using stream As New System.IO.FileStream(fu.PostedFile.FileName, IO.FileMode.Open, IO.FileAccess.Read)
            uri.FileName = fu.FileName
            uri.Length = fi.Length
            uri.FileByteStream = stream
            cu.UploadFile(uri)
        End Using
    End If
End Sub

谁能告诉为什么不能TransferService使用以下方法创建一个实例:

Dim cu As New ServiceReference1.TransferServiceClient()

如果我尝试上述方法,它将打破这一行:

cu.UploadFile(uri)

...并且 UploadFile 必须使用三个参数(文件名、长度、文件字节流)调用,即使没有使用此签名的方法。

请问创建这个类的实例时为什么需要接口?

4

2 回答 2

2

当您使用“添加服务引用”对话框为您的服务创建代理时,默认情况下,代理创建代码将“解包”消息合同,就像您拥有的那样。如果您希望消息合同按照您在代理服务器端的定义显示,您需要选择“高级”选项卡,并选中“始终生成消息合同”选项。这样,您也将在客户端中获得消息合同。

于 2013-01-03T20:00:45.607 回答
1

问题是,当MessageContract遇到 a 作为参数时,WCF 客户端生成默认情况下假定您要实现消息传递样式的接口,并提供消息协定中的离散属性作为客户端接口的一部分。

MSDN 中的Using Messaging Contracts文章非常详细地描述了使用消息合同可以做什么,我怀疑 Microsoft 之所以选择这种默认行为是因为您可以使用这些消息玩一些“游戏”。

但是,如果您在客户端检查为 UploadFile 生成的代码,就会发现一些有趣的花絮有助于解释发生了什么。

首先是接口中UploadFile方法的注释:

    'CODEGEN: Generating message contract since the operation UploadFile is neither RPC nor document wrapped.
    ...
    Function UploadFile(ByVal request As ServiceReference1.RemoteFileInfo) As ServiceReference1.UploadFileResponse

这意味着如果消息合约有不同的实现,合约的生成方式也会不同。

第二个是您将看到用于实际进行服务调用的代码没有什么特别之处:

    Public Sub UploadFile(ByVal FileName As String, ByVal Length As Long, ByVal FileByteStream As System.IO.Stream)
        Dim inValue As ServiceReference1.RemoteFileInfo = New ServiceReference1.RemoteFileInfo()
        inValue.FileName = FileName
        inValue.Length = Length
        inValue.FileByteStream = FileByteStream
        Dim retVal As ServiceReference1.UploadFileResponse = CType(Me,ServiceReference1.ITransferService).UploadFile(inValue)
    End Sub

因此,在这种情况下,您的代码与生成的代码完全一样。但是,如果 MessageContract 更复杂,我怀疑情况将不再如此。

所以,对于你的问题:

谁能告诉为什么不能使用以下方法创建 TransferService 的实例...

只要您验证方法调用的实现与您的代码功能等效,就没有理由不采用这种方法。

有几个选项可以更改客户端中方法的默认生成:

1)MessageContract从类中删除属性RemoteFileInfo

2) 虽然看起来有违直觉,但您可以选中Configure Service Reference Dialog BoxAlways generate message contracts中的复选框。

于 2013-01-04T02:56:56.463 回答