2
votes

Periodically, the duplex Net.TCP connection between our Silverlight application and our WCF web service will enter the faulted state -- for instance, due to transient network issues, or if the service crashes and restarts, things like that. When that happens, I'd like to catch this, and re-open the connection. Sounds straightforward, right? You should be able to do something like this:

private void Channel_Faulted(object sender, EventArgs e)
{
    client.CloseCompleted += (sender, e) =>
        {
            if (e.Error == null)
                client = CreateClient();
            else
                Debug.WriteLine(e.Error.ToString());
        };
    client.CloseAsync();
}

But when I try that the e.Error in the CloseCompleted handler has this exception:

The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.

I've tried a whole bunch of variations on this same theme, including:

  • Not closing the connection after it faults and just recreating it.
  • Calling client.InnerChannel.Close() and/or client.ChannelFactory.Close() manually.
  • calling client.InnerChannel.Dispose() and/or client.ChannelFactory.Dispose() manually.
  • Lots of other stuff that I've forgotten now.

These strategies have resulted in a variety of errors, but none of have worked correctly, including the sort of non-Silverlight solutions mentioned, say, here or here (but all for regular CLR apps, not Silverlight). Surely this is a fairly straightforward thing to do, but apparently the channel caching is getting in my way. What am I missing? What's the right way to do this in Silverlight? If this is a bug in Silverlight, what's the right workaround?

1

1 Answers

1
votes

As with most things that seem to be working in inexplicable ways, the problem was my fault. The actual code I'm working with is (not surprisingly, I hope) significantly more complicated than the simplified version I posted above. And it turns out that in my real code, in the particular code path that I was testing, the equivalent of this line was never being called:

client = CreateClient();

In other words, the client wasn't actually getting recreated after throwing a fault, and the errors I was running into primarily resulted from trying to re-use an old instance. Sorry for the fuss.