Reputation: 354
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
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
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