2012-12-19 83 views
2

我正在編寫一個WCF WebMethod來上傳文件,其中我從網絡上截取了一些片段。 WCF的接口看起來是這樣的:在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() 

如果我嘗試ABOV E,它打破了這一行:

cu.UploadFile(uri) 

...並UploadFile必須有三個參數(文件名,長度,FileByteStream)甚至存在使用這個簽名沒有方法被調用。

爲什麼在創建這個類的實例時需要接口?

回答

1

問題是,當遇到MessageContract作爲參數時,WCF客戶端生成默認情況下假定您要實現消息傳遞式接口,並提供消息協定中的離散屬性作爲客戶端的一部分,側面的界面。

MSDNDN中的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)從RemoteFileInfo類取出MessageContract屬性。 2)儘管它看起來與直覺相反,但您可以在Configure Service Reference Dialog Box中檢查Always generate message contracts複選框。

+0

哇 - 驚人的答案 - 謝謝!關於您的評論: _ >>從RemoteFileInfo類中刪除MessageContract屬性<< _ 我需要用DataContractAttribute替換它嗎? 另外,請您詳細說明可以玩什麼「遊戲」?作爲WCF的新手,我希望得到任何額外的建議,即使這意味着更多的閱讀......!再次感謝 – EvilDr

+1

Re RemoteFileInfo:是的,最好使用DataContract,儘管它並不是嚴格要求的,因爲WCF會自動處理普通的類對象(PO​​CO)。重新遊戲:我主要指的是可以操縱底層SOAP消息的多種方式(加密部件,使用不同的名稱空間,使用不同的序列化引擎等),這些方式可能會對客戶端生成的消息產生影響,也可能不會產生影響代碼(請參閱MSDN文章以深入討論各種功能)。 –

+0

超級。非常感謝您的詳細回覆。 – EvilDr

2

當您使用「添加服務引用」對話框爲您的服務創建代理時,默認情況下,代理創建代碼將「展開」消息合約,如您擁有的代碼。如果您希望消息合約按照您在代理服務器上定義的方式顯示,則需要選擇「高級」選項卡,然後選中「始終生成消息合約」選項。有了這個,你也可以在你的客戶端獲得消息合約。