What Is the Best Workaround For the Wcf Client 'Using' Block Issue

What is the best workaround for the WCF client `using` block issue?

Actually, although I blogged (see Luke's answer), I think this is better than my IDisposable wrapper. Typical code:

Service<IOrderService>.Use(orderService=>
{
orderService.PlaceOrder(request);
});

(edit per comments)

Since Use returns void, the easiest way to handle return values is via a captured variable:

int newOrderId = 0; // need a value for definite assignment
Service<IOrderService>.Use(orderService=>
{
newOrderId = orderService.PlaceOrder(request);
});
Console.WriteLine(newOrderId); // should be updated

Problems with the Using Statement and WCF client

The core of the problem is: at the end of your using block (which generally is a very good idea to have!), the WCF proxy will be disposed. However, during disposing of the WCF proxy, exceptions can occur - and those will cause the app to misbehave. Since this is done implicitly at the end of the using block, you might not even really see where the error occurs.

So typically, Microsoft recommends a pattern something like this:

private ServiceClient proxy;

try
{
proxy = new ServiceClient("ConfigName", "http://serviceaddress//service.svc");
string result = proxy.Method();
proxy.Close();
}
catch (CommunicationException e)
{
// possibly log error, possibly clean up
proxy.Abort();
}
catch (TimeoutException e)
{
// possibly log error, possibly clean up
proxy.Abort();
}
catch (Exception e)
{
// possibly log error, possibly clean up
proxy.Abort();
throw;
}

You need to call the proxy.Close() method explicitly and be prepared to handle any exceptions that might occur from that call, too.

Disposing of a WCF client instantiated via an interface

I recently wrote an article about the correct handling of a WCF client's life cycle: Only wrapping the instantiation in a using block is not sufficient...

Have a look at http://blog.rsuter.com/?p=975

Summary: Overload Dispose the following way to use the client with the using keyword:

public void Dispose()
{
if (isDisposed)
return;

try
{
if (service.State == CommunicationState.Faulted)
service.Abort();
else
{
try
{
service.Close();
}
catch (Exception closeException)
{
try
{
service.Abort();
}
catch (Exception abortException)
{
throw new AggregateException(closeException, abortException);
}
throw;
}
}
}
finally
{
isDisposed = true;
}
}

Does the C# WCF Proxy ClientBaseT Disposal issue still exist in .Net 4.5+

UPDATE: I've just found this... https://msdn.microsoft.com/en-us/library/aa355056(v=vs.110).aspx ...which suggests it's still an issue.

WCF Client - Best Practise

Visual Studio Generator

You can ask Visual Studio to build a client for you, right-clicking your client project and adding a Service Reference. There's a dialog where you can either type your service url or discover it from within the solution.

Creating a Client

You can build the client class inheriting from ClientBase<ISecurityManager>, ISecurityManager. Being an operation example on this client class:

public void ExampleMethod(int id)
{
Channel.ExampleMethod(id);
}

Like a real man does

Or without any client class, just calling it:

ServiceInvokerinvoker invoker = new ServiceInvoker(); 
var result = invoker.InvokeService<ISecurityManager, ReturnType>( proxy => proxy.ExampleMethod(1) );

Last two options assuming you already have configured the ISecurityManager client:

<client>     
<endpoint name="ServiceName"
address="http://ServiceName.test/Service"
binding="basicHttpBinding"
contract="ISecurityManager" />
</client>

Best approach for WCF client

The first question is whether your server needs to maintain any state about the client directly (i.e. are you doing session-like transactions?) If you are, you will need to be able to manage how the server holds the information between communications.

My initial feeling of your question is that if there is no need to leave a connection open, then close it each time and recreate a new connection on demand. This will avoid issues where a connection can be placed into a faulted state between calls. The overhead of creating and destroying connections is minimal, and it will (probably) save you a lot of time in debugging when something goes wrong.

Disposing a WCF windows service client inside a WCF web service

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.



Related Topics



Leave a reply



Submit