2017-02-13 5 views
0

私は、別のマシン上のWCF WindowsサービスにアクセスするWCF Webサービスを持っています。 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

はいdisposeは使用しないでください。このようにそれを実行します。クライアント上Close()を呼び出す

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(); 
} 

は、それが使用されなくなったとGC(サービスインスタンスの管理対象)によって収集することができることをサービスインスタンスに通知していません。

なぜAbortcatchブロックにあるのだろうか?理由は次のとおりです。

WCFバインディングでは、トランスポートセッションを使用すると、フォルトが発生してもクライアントはそれを閉じることができません(トランスポートレイヤセッションがない場合、クライアントはプロキシを使用または閉じることができますこれは、セッションの構成が変更される可能性があるため推奨されません)。したがって、障害が発生した後は、唯一の安全な操作はプロキシを中止することです。

AbortCloseの詳細についてはthisを参照してください。あなたのコメントで


EDIT

あなたは尋ねた:

を、あなたは、Webサービスは、Windowsサービスを呼び出すすべての関数内でこのようなサービスのクライアントを作成し、閉じてお勧めですか?

いいえ私は必要ではないと思います。ClientBase<TChannel>ICommunicationObjectを実装しているので、あなたは、コントローラのDispose方法でこのような何かをするだろう、あなたはWebアプリケーション(ASP MVC)からWCFサービスを呼び出している見てみましょう:

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()がスローすると、内部状態を 'Closed'に設定するAbort()が呼び出されます。 Dispose()を呼び出すと、Close()はClosedの状態で再び呼び出され、何もしません。 私は言った:明示的にクライアントを処分する必要はありませんが、本当に必要な場合は、上記のコードは安全な方法を示しています。 –

+0

ICommunicationObjectがClosing状態の場合、Close()はすぐに戻ります。したがって、ICommunicationObjectがフォルト状態になる可能性はありますが、Dispose()を呼び出すと例外が発生します。 –

関連する問題