1
Vote

Closed event of InnerChannel (which recreates the proxy) sometimes fires after second call to service in Invoke

description

Closed event of InnerChannel (which recreates the proxy) sometimes fires after second call to service in Invoke.
 

I have the following test that were running fine on my local dev machine:

var serviceStub = new Mock<SsoService>();
bool hasFaultedTheChannelOnce = false;
bool authenticated = false;
 
using (var host = TestHelpers.CreateAndInitializeServiceHost(serviceStub.Object))
{
using (var proxy = new SsoServiceProxy(new NetNamedPipeBinding(), new EndpointAddress(host.BaseAddresses[0])))
{
serviceStub.Setup(a => a.AuthenticateUser("user", "pass")).Returns(() =>
                                   {
                                      if (!hasFaultedTheChannelOnce)
                                       {
                                       hasFaultedTheChannelOnce = true;
                                       proxy.InnerChannel.Abort(); //simulating e.g. network problems on the first attempt
                                       }
                                       return true;
                                   }).AtMost(2).Verifiable();
 
SsoMembershipProvider provider = new SsoMembershipProvider(proxy);
authenticated = provider.ValidateUser("user", "pass");
}
}
 
Assert.That(hasFaultedTheChannelOnce, Is.True);
Assert.That(authenticated, Is.True);

serviceStub.VerifyAll();

 
However, when this was run on our buildserver, it failed and complained that the channel was faulted.
 
As I debugged it, it turned out that the second call to the service was called before the InnerChannels Closed event was fired.
 
Before calling the service a second time you wait for the m_proxyRecreationLock to be signalled so you can continue, however this flag should maybe be set already in the start of the Closing event of the InnerChannel?
 
void InnerChannel_Closing(object sender, EventArgs e)
{
  this.m_proxyRecreationLock.Reset(); // will stop other threads from trying to Invoke() while recreating the proxy
  (...)
 
At least this was a working temporary workaround for me. I am no expert in threading issues, so I suspect that my workaround can have issues that should be solved differently. E.g. doing a block in one event and releasing it in another has a little bit of a smell or...?
 
  • Freddy Hansen

comments