I have a very peculiar case here.
I have implemented a wsDualHttpBinding WCF duplex server that is being consumed by a Windows Service.
The contract and implementation on the server side is defined as follows:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class FixServerContract : IFixContract
{
public FixServerContract()
{
}
public void Requestlogin(string message)
{
try
{
IServerCallback callback = OperationContext.Current.GetCallbackChannel<IServerCallback>();
callback.BroadcastToClient("Greetings from server");
}
catch (Exception ex)
{
}
}
[ServiceContract(CallbackContract=typeof(IServerCallback))]
public interface IFixContract
{
[OperationContract]
void Requestlogin(string message);
}
public interface IServerCallback
{
[OperationContract(IsOneWay = true)]
void BroadcastToClient(string eventData);
}
On the client end, I also have a single callback class, with the attached callback interface accessed by adding a Service Reference to the Client project as follows:
class MyCallbackClass : IFixContractCallback
{
public void RegisterClient()
{
InstanceContext context = new InstanceContext(this);
FixContractClient proxy = new FixContractClient(context);
proxy.Requestlogin("hello");
}
public void BroadcastToClient(string eventData)
{
}
}
When proxy.RequestLogin("hello"); is called by the client, the server should respond by signaling BroadcastToClient(string eventData)
But, here is where the peculiar behavior begins!
When my client calls RegisterClient directly from Main, outside of a Winform or WPF environment, everything works as it should be. That is, RequestLogin is successfully called to the server, and the server successfully responds by signalling BroadcastToClient on the client end.
This is shown here:
[STAThread]
private static void Main(string[] args)
{
MyCallbackClass callbackClass = new MyCallbackClass();
callbackClass.RegisterClient();
}
However, when I do the following below simply by wrapping the above lines inside an button_Click handler in the Winform, this bug manifests itself with a crash:
[STAThread]
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
and then have a button click do the rest like so:
private void button1_Click(object sender, EventArgs e)
{
MyCallbackClass callbackClass = new MyCallbackClass();
callbackClass.RegisterClient();
}
then the following bug manifests itself:
1) RequestLogin is called on the server side, but the call to BroadcastToClient never reaches the client. Further to this, the RequestLogin never returns to client side, but instead, will timeout with the following exception:
2) An unhandled exception of type 'System.TimeoutException' occurred in mscorlib.dll. This request operation sent to XXXX did not receive a reply within the configured timeout (00:00:59.6359791). The time allotted to this operation may have been a portion of a longer timeout. This may be because the service is still processing the operation or because the service was unable to send a reply message. Please consider increasing the operation timeout (by casting the channel/proxy to IContextChannel and setting the OperationTimeout property) and ensure that the service is able to connect to the client.
The same behavior occurs if I use a WPF client. On the otherhand, it works perfectly if I use a Console based client!
Why does my Duplex Callback only work outside of a Winform or WPF?
How should I go about resolving this issue?
I am at my witts end here.
Thanks.
Kudos to this individual who has supplied me with an answer:
https://groups.google.com/forum/#!topic/microsoft.public.dotnet.framework.webservices/8Y6C8dRCFws
The solution is to modify MyCallbackClass as follows:
[CallbackBehavior(UseSynchronizationContext = false)]
class MyCallbackClass : IFixContractCallback
{
public void RegisterClient()
{
MyCallbackClass tester = this;
InstanceContext context = new InstanceContext(this);
FixContractClient proxy = new FixContractClient(context);
proxy.Requestlogin("hello");
}
public void BroadcastToClient(string eventData)
{
}
}