简体   繁体   中英

Change in one WCF service should update the same change in other instances of the same WCF services

I have multiple instances of the same WCF service hosted. If there is a change in one of the service instance then it should be notified/updated in other services too. I implemented the solution such that the WCF service acts as both client and server with the DuplexChannelFactory. But in order to do that the service needs to register its peers and I am doing that in the constructor of the service. This is leading to deadlock, since it is never going to get out initializing each other. How is this sort of logic can be implemented in WCF service?

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>());
            }
        }
    }
}

I would have a single separate WCF service that manages whatever data you're trying to keep synchronised across your services and have each service communicate with that.

Alternatively, you keep your data in a database so any change is automatically reflected across the services.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM