我托管了同一个WCF服务的多个实例。如果其中一个服务实例发生了变化,那么它也应该在其他服务中得到通知/更新。我实现了解决方案,使WCF服务充当客户端和服务器与DuplexChannelFactory。但是为了做到这一点,服务需要注册其对等体,我在服务的构造函数中这样做。这导致死锁,因为它永远不会相互初始化。如何在WCF服务中实现这种逻辑?
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Timers;
using WcfServiceLibrary.PeerServiceReference;
namespace WcfServiceLibrary
{
public interface IHeartbeat
{
bool Pulse();
void Ping();
}
[ServiceContract(CallbackContract = typeof(INotifications))]
public interface ISubscription : IHeartbeat, INotifications
{
[OperationContract(IsOneWay = true)]
void Subscribe(string ServiceName);
[OperationContract(IsOneWay = true)]
void Unsubscribe(string ServiceName);
}
[ServiceContract]
public interface INotifications
{
[OperationContract(IsOneWay = true)]
void UpdateData(int newValue);
}
[ServiceContract]
public interface IUserService
{
[OperationContract(IsOneWay = true)]
void MethodThatWillChangeData(int value);
}
public class ObservableService : IUserService, ISubscription
{
private static Dictionary<string, ISubscription> _Peers = new Dictionary<string, ISubscription>();
private int ClientAge;
private string ServiceName { get; }
private Timer _timer = new Timer() { Interval = 5000 };
private IWriter _writer;
public ObservableService() : this(new ConsoleWriter())
{
}
public ObservableService(IWriter writer)
{
_writer = writer;
_writer.WriteLine("Initiating construction...");
ServiceName = ConfigurationManager.AppSettings["ServiceName"];
_timer.Elapsed += Timer_Elapsed;
_timer.Start();
var PeerServersList = ConfigurationManager.AppSettings["PeerServers"].Split(';');
var callback = new InstanceContext(this);
foreach (var peer in PeerServersList)
{
try
{
var dualBinding = new WSDualHttpBinding();
var address = new EndpointAddress(peer);
var PeerServiceFactory = new DuplexChannelFactory<ISubscription>(callback, dualBinding);
var PeerService = PeerServiceFactory.CreateChannel(address);
PeerService.Subscribe(ServiceName);
}
catch (Exception ex)
{
//TODO handle the exception
}
}
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
_writer.WriteLine("Pinging the data");
this.Ping();
}
public void MethodThatWillChangeData(int newValue)
{
_writer.WriteLine($"MethodThatWillChangeData with {newValue}");
var PreviousClientAge = ClientAge;
ClientAge = newValue;
foreach (var peer in _Peers)
{
_writer.WriteLine($"Calling update on the client {peer.Key}");
peer.Value.UpdateData(newValue);
}
}
public void Ping()
{
var test = _Peers.Keys.ToList();
for (int i = _Peers.Count - 1; i >= 0; i--)
{
try
{
_writer.WriteLine($"Checking the pulse of {test[i]}");
_Peers[test[i]].Pulse();
}
catch (Exception)
{
_Peers.Remove(test[i]);
}
}
}
public bool Pulse()
{
_writer.WriteLine($"Pulse requested...");
return true;
}
public void UpdateData(int newValue)
{
_writer.WriteLine($"Updating the data to {newValue} from {ClientAge}");
ClientAge = newValue;
}
public void Unsubscribe(string ServiceName)
{
if (_Peers.Keys.Contains(ServiceName))
{
_Peers.Remove(ServiceName);
}
}
public void Subscribe(string ServiceName)
{
if (!_Peers.Keys.Contains(ServiceName))
{
_writer.WriteLine($"Registering {ServiceName}...");
_Peers.Add(ServiceName, OperationContext.Current.GetCallbackChannel<ISubscription>());
}
}
}
}
我将有一个单独的WCF服务,它管理您尝试在服务中保持同步的任何数据,并让每个服务与之通信。
或者,您将数据保存在数据库中,以便任何更改自动反映在服务中。