问题
In relation to Async two-way communication with Windows Named Pipes (.Net) which seems dead (the thread that is) :/
I'm wondering why the following code works perfectly in a ConsoleApplications, but when I do exactly the same thing with WindowsApplications I get an timeout on the client when calling "Console.WriteLine(proxy.ProcessData());". The strange thing is that the server method "ProcessData" is called without any exceptions, but still I get a timeout after the default 1 min?!
How can I fix this... and what exactly is the difference between between and ConsoleApp and a WinApp (besides the obvious) which is the reason something like this doesn't work?
Using WCF you can use duplex named pipes
// Create a contract that can be used as a callback
public interface IMyCallbackService
{
[OperationContract(IsOneWay = true)]
void NotifyClient();
}
// Define your service contract and specify the callback contract
[ServiceContract(CallbackContract = typeof(IMyCallbackService))]
public interface ISimpleService
{
[OperationContract]
string ProcessData();
}
Implement the Service
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class SimpleService : ISimpleService
{
public string ProcessData()
{
// Get a handle to the call back channel
var callback = OperationContext.Current.GetCallbackChannel<IMyCallbackService>();
callback.NotifyClient();
return DateTime.Now.ToString();
}
}
Host the Service
class Server
{
static void Main(string[] args)
{
// Create a service host with an named pipe endpoint
using (var host = new ServiceHost(typeof(SimpleService), new Uri("net.pipe://localhost")))
{
host.AddServiceEndpoint(typeof(ISimpleService), new NetNamedPipeBinding(), "SimpleService");
host.Open();
Console.WriteLine("Simple Service Running...");
Console.ReadLine();
host.Close();
}
}
}
Create the client application, in this example the Client class implements the call back contract.
class Client : IMyCallbackService
{
static void Main(string[] args)
{
new Client().Run();
}
public void Run()
{
// Consume the service
var factory = new DuplexChannelFactory<ISimpleService>(new InstanceContext(this), new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/SimpleService"));
var proxy = factory.CreateChannel();
Console.WriteLine(proxy.ProcessData());
}
public void NotifyClient()
{
Console.WriteLine("Notification from Server");
}
}
回答1:
The reason is synchronization context that is important when callback is called.
You call callback method from inside ProcessData
.
In case of console application there is no any synchronization context set, which means that WCF will call callback method on the client in the separate thread while main thread is waiting when ProcessData
returns. You can see this if you log thread ID in your console messages.
In case of Windows application main thread sets synchronization context (either WinForms or WPF). If you call your service from main thread, then WCF will try to call your callback method in the same synchronization context. But the only thread of this synchronization context is busy with waiting for ProcessData
to return.
You can solve that by two means:
1. Set UseSynchronizationContext=false
for your callback.
2. Call your service from background thread of the application - then callback will be called on some other threadpool thread.
Be aware that with both options you can't access UI elements from these background threads directly - you'll need to marshal calls to UI thread.
来源:https://stackoverflow.com/questions/43013991/wcf-named-pipes-timeout-in-a-winapp-but-not-in-a-consoleapp