2012-09-17 220 views
1

的我已經在這裏得到了快速概述:WCF服務的服務呼叫流端點上的第三個呼叫失敗

WCF SOAP服務正在運行通過HTTPS類型證書的信息憑證。我使用了2個端點(除了mex),其中1個用於我的普通服務調用,另一個用於流式文件。這裏是我的服務(編輯項目的一些名)的web.config:

<bindings> 
    <wsHttpBinding> 
    <binding name="wsHttpEndpointBinding"> 
     <security mode="TransportWithMessageCredential"> 
     <message clientCredentialType="Certificate" /> 
     </security> 
    </binding> 
    </wsHttpBinding> 
    <basicHttpBinding> 
     <binding name="streamBinding" transferMode="Streamed" messageEncoding="Mtom" maxReceivedMessageSize="2147483646"> 
      <security mode="TransportWithMessageCredential"> 
       <message clientCredentialType="Certificate" /> 
      </security> 
     </binding> 
    </basicHttpBinding>   
</bindings> 
<services> 
    <service behaviorConfiguration="Services.Behavior" name="MyInterface"> 
    <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" name="wsHttpEndpoint" contract="IMyInterface" /> 
    <endpoint address="stream" binding="basicHttpBinding" bindingConfiguration="streamBinding" name="streamEndpoint" contract="IMyInterface" /> 
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 
    </service> 
</services> 
<behaviors> 
    <serviceBehaviors> 
    <behavior name="Service.Behavior"> 
     <serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" /> 
     <serviceDebug includeExceptionDetailInFaults="true" /> 
     <dataContractSerializer maxItemsInObjectGraph="2147483646" /> 
     <serviceCredentials> 
     <serviceCertificate findValue="CN=Server.Temp.Dev" /> 
     </serviceCredentials> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 

服務有一個方法,DownloadDocument,我是測試。下面是簽名:

DocumentDownloadResponse DownloadDocument(DocumentDownloadRequest要求);

值得注意的服務拋出異常時傳遞的數據是無效的,和DownloadDocument捕捉那些異常和傳遞迴響應對象的錯誤消息。

的DocumentDownloadRequest看起來是這樣的:

[MessageContract] 
public class DocumentDownloadRequest 
{ 
    [MessageHeader] 
    public string SecurityToken { get; set; } 

    [MessageHeader] 
    public string LoginName { get; set; } 

    [MessageHeader] 
    public string DocumentId { get; set; } 
} 

而且DownloadDocumentResponse:

[MessageContract] 
public class DocumentDownloadResponse : ServiceResponse<Stream> 
{ 
    public DocumentDownloadResponse() 
    { 
     Data = Stream.Null; 
    } 

    [MessageHeader(MustUnderstand = true)] 
    public bool Success { get; set; } 

    [MessageHeader(MustUnderstand = true)] 
    public string ErrorMessage { get; set; } 

    [MessageBodyMember(Order = 1)] 
    public Stream Data { get; set; } 
} 

以下是我把它從客戶端:

 var soapServiceClient = new SoapServiceClient("streamEndpoint"); 
     bool success; 
     Stream stream; 
     string errorMessage = 
      soapServiceClient.DownloadDocument(documentId, loginName, securityToken, out success, out stream); 

     serviceClient.Close(); 

凡SecurityToken而LoginName是項需要驗證。奇怪的是,從我的測試客戶端,當我使用有效數據調用DownloadDocument時,我能夠按照需要完美地下載文件。但是,如果我傳遞了無效的LoginName或SecurityToken,則會收到指示錯誤數據的錯誤消息(如預期的那樣)。但是,如果我傳遞3次無效數據,則客戶端會超時。在本地運行服務我沒有遇到這個問題,everythign按預期運行。奇怪的是,當我開着小提琴手跑時,我不明白這個問題。當我使用我的開發服務器上的服務運行時,我遇到了問題。

開發服務器上的配置與我在本地運行的配置相匹配。使用SvcTraceTool我沒有看到任何錯誤,只是它只記錄前2次成功的調用,而不是失敗的調用。這幾乎讓我覺得端點只是以某種方式關閉了自己。

懸崖:

1)2個終點,如果這是流之一(一個我很擔心)服務。 2)可以使用流式端點調用方法下載帶有效數據的文件 3)服務正確捕獲不良數據2次,掛起第3次。 SvcTraceTool中沒有日誌,客戶端超時。

任何想法?

感謝

+0

任何積極的結果? –

+1

是的,事實證明,在寫入文件後,我沒有正確關閉客戶端的數據流。另外,在服務端發生錯誤的情況下,我返回Stream.Null,這也需要關閉。 – TheTFo

+0

很好,謝謝。但爲了以防萬一,你能告訴我關閉流的正確方式/順序是什麼? –

回答

2

爲了回答羅德里戈,我想我會發布更多的細節:

首先,包裝你生成的代理類的東西有點像這對正確處理錯誤:

public class ProxyWrapper<TServiceClientType, TResultType> 
    where TServiceClientType : class, ICommunicationObject 
{ 
    private static string _endPoint; 

    public ProxyWrapper(string endPoint = "") 
    { 
     _endPoint = endPoint; 
    } 

    public TResultType Wrap(Func<string, TServiceClientType> constructWithEndpoint, 
            Func<TServiceClientType, TResultType> codeBlock) 
    { 
     TResultType result = default(TResultType); 
     TServiceClientType client = default(TServiceClientType); 
     try 
     { 
      client = constructWithEndpoint(_endPoint); 
      result = codeBlock(client); 
      client.Close(); 
     } 
     catch (Exception) 
     { 
      if (client != null) 
      { 
       client.Abort(); 
      } 
      throw; 
     } 
     return result; 
    } 
} 

然後我有一個客戶端類包裝服務調用。這裏的DownloadDocument方法:

public MyServiceResponse<Stream> DownloadDocument(string loginName, 
                  string documentId) 
    { 

     var proxyWrapper = new MyProxyWrapper<DocumentDownloadResponse>(StreamEndpoint); 
     DocumentDownloadResponse response = 
      proxyWrapper.Wrap((client) => 
      { 
       Stream data; 
       bool success; 
       string errorMessage = client.DownloadDocument(documentId, loginName, 
                   out success, 
                   out data); 
       return new DocumentDownloadResponse 
       { 
        Data = data, 
        Success = success, 
        ErrorMessage = errorMessage 
       }; 
      }); 

     var result = new MyServiceResponse<Stream> 
     { 
      Success = response.Success, 
      ErrorMessage = response.ErrorMessage 
     }; 

     if (!response.Success) 
     { 
      result.Data = null; 
      response.Data.Close(); 
     } 
     else 
     { 
      result.Data = response.Data; 
     } 

     return result; 
    } 

注:MyProxyWrapper從ProxyWrapper繼承和指定的WCF客戶端代理類。現在的實際調用看起來是這樣的:

var myClient = new MyClient(); 
var downloadDocumentResponse = myClient.DownloadDocument(someId); 
           using (
            Stream output = 
             File.OpenWrite(someFilePath)) 
           { 
            downloadDocumentResponse.Data.CopyTo(output, 2048); 
            downloadDocumentResponse.Data.Close(); 
           } 

需要注意的是,我稱之爲.Close()在流,寫入文件後一次,而一旦這兩個地區是response.Success ==假。

+0

令人驚歎。非常感謝!我會看看流關閉。 –