2017-02-13 159 views
0

我有一個WCF Web服務訪問另一臺計算機上的WCF Windows服務。 Windows服務執行所有數據訪問並將結果傳遞給Web服務。我已閱讀了幾篇關於正確處理WCF服務的服務客戶端的文章,但我不確定在Web服務中執行此操作的最佳方式是什麼。 (如果這會有所幫助,Web服務是PerCall不PerSession)在WCF Web服務內部處理WCF Windows服務客戶端

這是我現在在做:

Public Class Service1 
    Implements IService1 

    Private p_oWindowsService As DataService.Service1Client 

    Public Sub New() 
    p_oWindowsService = New DataService.Service1Client 
    End Sub 

    Public Function GetData(ByVal value As Integer) As String Implements IService1.GetData 
    Return p_oWindowsService.GetData(value) 
    End Function 

    Public Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType Implements IService1.GetDataUsingDataContract 
    If composite Is Nothing Then 
     Throw New ArgumentNullException("composite") 
    End If 
    If composite.BoolValue Then 
     composite.StringValue &= "Suffix" 
    End If 
    Return composite 
    End Function 

我不處置服務客戶端在現在好了,從我已經讀過這是一個重大問題。我在看的解決方法是這樣的事情的GetData函數內部:

Public Function GetData(ByVal value As Integer) As String Implements IService1.GetData 
    Using oWindowsService As New DataService.Service1Client 
     Return oWindowsService.GetData(value) 
    End Using   
    End Function 

基於關閉What is the best workaround for the WCF client `using` block issue?,我知道我不應該實際上取決於使用塊。但是,我應該在每個功能中創建和部署服務客戶端嗎?這是我真正的問題。

謝謝。

回答

2

是不使用處置。像這樣做:

var client = new ...; 
try { 
    // Do work 

    // Everything went well so close the client 
    client.Close(); 
} 
catch(Exception ex) { 
    // Something went wrong so call abort 
    client.Abort(); 

    // Other logging code 
} 

if(client.State != System.ServiceModel.CommunicationState.Closed) { 
    client.Close(); 
} 

調用客戶端Close()通知服務實例,它不再使用,並且可以由GC(加收服務實例管理)進行收集。

您可能會奇怪爲什麼Abortcatch塊?其原因是:

鑑於WCF結合使用傳輸會話,一個故障後,客戶端將甚至無法將其關閉(如果沒有傳輸層會話,然後客戶端可以使用或關閉代理,但這是不推薦的,因爲會話的配置可能會改變)。所以在發生故障之後,唯一安全的操作是中止代理。

更多關於Abort VS Closethis


編輯

在你的意見,你問:

你建議創建並在每次關閉服務客戶端這樣的函數調用Web服務的窗口服務?

不,我不認爲這是必要的。讓我們來看看您呼叫從一個Web應用程序(ASP MVC)的WCF服務,那麼你會做控制器的Dispose方法是這樣的,因爲ClientBase<TChannel>工具ICommunicationObject

protected override void Dispose(bool disposing) { 
    base.Dispose(disposing); 

    ServiceHelper.DisposeService((this._whateverServiceClient as ICommunicationObject)); 
} 

這裏是ServiceHelper類你可以從任何地方使用:

public static class ServiceHelper { 

    /// <summary> 
    /// Disposes the given service. 
    /// </summary> 
    /// <param name="service">The service.</param> 
    public static void DisposeService(ICommunicationObject service) { 

    if(service != null) { 

     bool abort = true; 

     try { 
      if(service.State == CommunicationState.Opened || service.State == CommunicationState.Opening) { 
       service.Close(); 
       abort = false; 
      } 
     } 
     finally { 

      // Determine if we need to Abort the communication object. 
      if(abort) 
       service.Abort(); 
     } 
    } 
    } 

}

的想法是相同的,如果你是從另一個客戶端調用它。

+0

你建議創建和關閉一個服務客戶端一樣這個web服務在每個函數中調用windows服務? – cjw

+0

@cjw請參閱編輯答案。 – CodingYoshi

0

你並不需要明確地配置客戶端,如果你真的要怎麼過,這是正確關閉&處置你的客戶的一種方式:

 // use client 
     try 
     { 
      ((IClientChannel)client).Close(); 
     } 
     catch 
     { 
      ((IClientChannel)client).Abort(); 
     } 
     finally 
     { 
      ((IDisposable)client).Dispose(); 
     } 
+0

在finally塊中調用Dispose()會引起麻煩。 Dispose()調用Close(),如果通道出現故障,可能會引發異常。 –

+0

我提供的代碼示例是安全的,不會丟失。如果Close()拋出,Abort()將被調用,將內部狀態設置爲'Closed'。在調用Dispose()時,Close()將再次被調用,狀態爲Closed,這將不會執行任何操作。 就像我說的:你不需要明確地處理客戶端,但如果你真的必須,上面的代碼顯示了一個安全的方式。 –

+0

如果ICommunicationObject處於關閉狀態,則Close()將立即返回。因此,ICommunicationObject仍然有可能出現故障,此時調用Dispose()將導致異常。 –