cjw
cjw

Reputation: 354

Disposing a WCF windows service client inside a WCF web service

I have a WCF web service that accesses a WCF windows service on a different machine. The windows service does all the data accessing and passes the results to the web service. I have read several articles about disposing the service client for a WCF service correctly, but I'm not sure what the best way is to do this in a web service. (If this helps, the web service is PerCall not PerSession)

This is all I'm doing right now:

 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

I'm not disposing the service client at all right now, from what I've read this is a major issue. The workaround I'm looking at is something like this inside the GetData function:

 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

Based off What is the best workaround for the WCF client `using` block issue?, I know I shouldn't actually depend on the using block. But should I be creating and disposing a service client in every function? That's my real question.

Thank you.

Upvotes: 1

Views: 1550

Answers (2)

Jorge Del Conde
Jorge Del Conde

Reputation: 361

You don't need to explicitly dispose the client, how ever if you truly must, this is one way of properly closing & disposing your client:

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

Upvotes: 0

CodingYoshi
CodingYoshi

Reputation: 27009

Yes do not use dispose. Do it like this:

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

Calling Close() on client notifies the service instance that it is no longer in use and may be collected by GC (subject to service instance management).

You may wonder why Abort in the catch block? The reason is:

Given the WCF binding use transport sessions, the client after a fault would not even be able to close it (if there was no transport layer session then the client could use or close the proxy, but this is not recommended as the configuration of sessions could change). So after a fault has happened the only safe operation is to abort a proxy.

See this for more on Abort vs Close.


EDIT

In your comments you asked:

Do you recommend creating and closing a service client like this within every function the web service calls the windows service?

No I don't think that is necessary. Let's see you are calling the WCF service from a web application (ASP MVC), then you would do something like this in the Dispose method of the controller since ClientBase<TChannel> implements ICommunicationObject:

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

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

And here is the ServiceHelper class that you can use from anywhere:

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

}

The idea would be the same if you were calling it from another client.

Upvotes: 2

Related Questions