I have this strange problem where my client will hang when it calls a method from my WCF Service. Now the real strange thing is that this does not happen when the Client is a Console Application. It does happen when the client is a WinForm or WPF application.
I created a Client Library that a WCF Client can use to connect to the Service, seen here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel; //needed for WCF communication
namespace DCC_Client
{
public class DCCClient
{
private DuplexChannelFactory<ServiceReference1.IDCCService> dualFactory;
public ServiceReference1.IDCCService Proxy;
public DCCClient()
{
//Setup the duplex channel to the service...
NetNamedPipeBinding binding = new NetNamedPipeBinding();
dualFactory = new DuplexChannelFactory<ServiceReference1.IDCCService>(new Callbacks(), binding, new EndpointAddress("net.pipe://localhost/DCCService"));
}
public void Open()
{
Proxy = dualFactory.CreateChannel();
}
public void Close()
{
dualFactory.Close();
}
}
public class Callbacks : ServiceReference1.IDCCServiceCallback
{
void ServiceReference1.IDCCServiceCallback.OnCallback(string id, string message, Guid key)
{
Console.WriteLine(string.Format("{0}: {1}", id, message));
}
}
}
Here is the code for the working WCF Console Client:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DCC_Client;
namespace Client_Console_Test
{
class Program
{
private static DCCClient DCCClient;
static void Main(string[] args)
{
try
{
DCCClient = new DCCClient();
DCCClient.Open();
DCCClient.Proxy.DCCInitialize(); //returns fine from here
Console.ReadLine();
DCCClient.Proxy.DCCUninitialize();
DCCClient.Close();
}
catch (Exception e)
{
throw;
}
}
}
}
And here is the code for the WPF Client that freezes (see comment)
using System; //etc
using DCC_Client; //Used for connection to DCC Service
namespace Client_WPF_Test
{
public partial class Main : Window
{
private static DCCClient DCCClient;
public Main()
{
InitializeComponent();
DCCClient = new DCCClient();
DCCClient.Open();
}
private void Connect_btn_event() {
try
{
DCCClient.Proxy.DCCInitialize(); //**never returns from this**
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
I stepped into the code DCCClient.Proxy.DCCInitialize();
and the service executes the commands successfully, however, for some reason the client gets stuck here and does not continue executing. The client gives no exception, and the stack trace says [external code].
That being said, the Console Client runs perfectly. I think I am missing something simple here. I appreciate any help you can provide.
In case that your service call backs the client directly from DCCInitialize
and both operation and callback operation are not marked as one-way your application will deadlock. Try marking your callback implementation with this attribute:
[CallbackBehavior(ConcurrencyMode=ConcurrencyModel.Reentrant)]
Instead of this you can also try to mark operations in both contracts with
[OperationContract(IsOneWay=true)]
But both operations must return void
For the last if neither of these helps try to mark your callback implementation with:
[CallbackBehavior(UseSynchronizationContext=false)]
but in this case your callback operation will run in another thread and it will not be able to manipulate with UI controls directly.
Edit:
WCF behaves differently when hosted in UI thread. In such scenario all request are processed in sequential order in standard windows message loop so if you call the service you blocked your current thread but the service calls back your client and it waits to process the message but it can't because thread is blocked by the initial call = deadlock until initial request timenouts. By using last mentioned behavior you will say WCF to not join windows message loop and instead process messages in separate threads as usual. There is no security issue with this except the fact that you cannot access UI control from methods running in other threads - both WinForms and WPF has approaches to pass commands from other thread.