9
votes

I use WCF for a client server system. When I add a service reference to IService on the server, a proxy class ServiceClient is generated. My code looks like the following:

ServiceClient client = new ServiceClient();
try
{
    client.Operation1();
}
catch(Exception ex)
{
    // Handle Exception
}
try
{
    client.Operation2();
}
catch(Exception ex)
{
    // Handle Exception
}

The problem is that if there is a communication exception in the first call, the client's state changes to Faulted, and I don't know how to reopen it to make the second call. Is there a way to reopen it? or should I create a new one and replace the instance (It doesn't seem like an elegant way)?

4

4 Answers

16
votes

Once a an ICommunicationObject (your WCF client object) is in a faulted state, the only way to "re-open" it is to create a new one.

ServiceClient client = new ServiceClient();
try
{
    client.Operation1();
}
catch(Exception ex)
{
    if (client.State == CommunicationState.Faulted)
    {
            client.Abort();
            client = new ServiceClient();
    }
}
try
{
    client.Operation2();
}
catch(Exception ex)
{
   // Handle Exception
}
6
votes

If there is a communication exception on the first call which is causing a faulted state, you have to basically "re-create" the WCF client proxy. In your example I would probably do something like:

if (client.State == CommunicationState.Faulted)
    client = new ServiceClient();

This would allow you to "re-open" the connection if it is faulted. It may seem a little overkill, but if you're getting a communication exception on the client side, there's probably something else going on (i.e.: server dead? server not responding?)

Good luck

4
votes

Agree with the last answers, once failed, you need to abort. We use a combination of lambdas and a method like the following to do this:

  public static void Use<TServiceInterface>(TServiceInterface proxy, Action handler)
  {
     Type proxyType = typeof(TServiceInterface);
     IClientChannel channel = (IClientChannel)proxy;

     try
     {
        handler();

        _logSource.Log(LogLevel.Debug, string.Format("Closing client channel for '{0}' ...", proxyType.Name));

        channel.Close();

        _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' closed.", proxyType.Name));
     }
     catch
     {
        if (channel.State == CommunicationState.Faulted)
        {
           _logSource.Log(LogLevel.Debug, string.Format("Aborting client channel for '{0}' ...", proxyType.Name));

           channel.Abort();

           _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' aborted.", proxyType.Name));
        }
        else
        {
           _logSource.Log(LogLevel.Debug, string.Format("Closing client channel for '{0}' ...", proxyType.Name));

           channel.Close();

           _logSource.Log(LogLevel.Debug, string.Format("Client channel for '{0}' closed.", proxyType.Name));
        }

        throw;
     }
  }

This is a slight modification of a solution that is already on the .net, but it works great for handling proxies. You then can put multiple service calls in the same lambda expression, and pass it into the method.

0
votes

This is most likely caused by an unhandled exception on the server side. WCF runtime by default terminates your service instance and puts the channel in faulted state in case of unhandled exception and you can no longer communicate over that channel. So you will need to establish a new session with the service. You should catch exceptions on the server side and send the soap faults by raising FaultException or defining FaultContract. There is also returnUnknownExceptionsAsFaults service behavior that you can use.