Итак, у меня есть простой тестовый сервис WCF.Идея состоит в том, что один процесс вызывает другой и регистрируется для обратных вызовов, а другой затем вызывает исходный вызывающий объект, когда происходят события.Собственные обратные вызовы WCF не работают должным образом или для этого приложения, так что не беспокойтесь об этом.У меня есть очень простая тестовая программа, которая демонстрирует поведение.Каждые 10 попыток, он приостанавливается на некоторое время (период ожидания) и восстанавливается после него.Он восстанавливается без запуска каких-либо событий канала - открыть / закрыть / что угодно.Я должен что-то упустить, очевидно, но что ...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Threading;
namespace WCFTest
{
[ServiceContract(Namespace = "http://WCF.WTF")]
public interface IServerEvents
{
[OperationContract(IsOneWay = true)]
void Heartbeat();
}
[ServiceContract(Namespace = "http://WCF.WTF")]
public interface ICallbackEvents
{
[OperationContract(IsOneWay = true)]
void HeartbeatAck();
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
[CallbackBehavior(IncludeExceptionDetailInFaults = true)]
class Program : IServerEvents, ICallbackEvents
{
static AutoResetEvent CalledBack = new AutoResetEvent(false);
static ChannelFactory<IServerEvents> ServerChannelFactory;
static ChannelFactory<ICallbackEvents> ClientChannelFactory;
static ServiceHost ServerHost;
static ServiceHost ClientHost;
static int Timeout = 5;
private Program()
{
}
static void Main(string[] args)
{
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None)
{
OpenTimeout = new TimeSpan(0, 0, Timeout),
SendTimeout = new TimeSpan(0, 0, Timeout),
ReceiveTimeout = new TimeSpan(0, 0, Timeout),
MaxConnections = 50,
ListenBacklog = 50
};
Uri serverUri = new Uri("net.tcp://localhost:3123/WTF");
ServerChannelFactory = new ChannelFactory<IServerEvents>(binding, new EndpointAddress(serverUri));
ClientChannelFactory = new ChannelFactory<ICallbackEvents>(binding, new EndpointAddress("net.tcp://localhost:3123/WTF/Client"));
ServerChannelFactory.Closing += new EventHandler((s,x) => Console.WriteLine("SClosing"));
ServerChannelFactory.Opening += new EventHandler((s, x) => Console.WriteLine("SOpening"));
ServerChannelFactory.Faulted += new EventHandler((s,x)=> Console.WriteLine("SFaulted"));
ClientChannelFactory.Closing += new EventHandler((s, x) => Console.WriteLine("CClosing"));
ClientChannelFactory.Opening += new EventHandler((s, x) => Console.WriteLine("COpening"));
ClientChannelFactory.Faulted += new EventHandler((s, x) => Console.WriteLine("CFaulted"));
ServerHost = StartServer("/Server", new Program(), typeof(IServerEvents));
ClientHost = StartServer("/Client", new Program(), typeof(ICallbackEvents));
while (true)
{
Thread.Sleep(100);
try
{
new Program().Heartbeat();
if (!CalledBack.WaitOne(2500, true))
{
throw new TimeoutException("Epic fail.");
}
}
catch (Exception x)
{
Console.WriteLine("Failed heartbeat.\n{0}", x);
}
}
}
public void Heartbeat()
{
Console.Write(".");
Console.Out.Flush();
try
{
ClientChannelFactory.CreateChannel().HeartbeatAck();
}
catch (Exception x)
{
Console.WriteLine("Couldn't ACK heartbeat.\n{0}", x);
}
}
public void HeartbeatAck()
{
Console.Write("!");
Console.Out.Flush();
CalledBack.Set();
}
private static ServiceHost StartServer<T>(string fragment, T remoteObject, Type interfaceType)
{
ServiceHost retHost = null;
using (AutoResetEvent revent = new AutoResetEvent(false))
{
bool hostOk = false;
// The service host has to be started on a non-sync-context thread or bad things (tm) will happen.
ThreadPool.QueueUserWorkItem((oo) =>
{
try
{
retHost = new ServiceHost(remoteObject, new Uri("net.tcp://localhost:3123/WTF"));
var binding = new NetTcpBinding(SecurityMode.None)
{
OpenTimeout = new TimeSpan(0, 0, Timeout),
SendTimeout = new TimeSpan(0, 0, Timeout),
ReceiveTimeout = new TimeSpan(0, 0, Timeout),
MaxConnections = 50,
ListenBacklog = 50
};
retHost.AddServiceEndpoint(interfaceType, binding, fragment);
retHost.Open();
hostOk = true;
}
catch (Exception xc)
{
Console.WriteLine("Couldn't start WCF Service Host!\n{0}", xc);
}
finally
{
try { revent.Set(); }
catch { }
}
});
revent.WaitOne(5000, true);
return hostOk ? retHost : null;
}
}
}
}