Sunday 20 October 2013

WCF - Create a Publisher and Subscriber model by various Cricket notification from Service to client.




What is Publisher and Subscriber model ?
   Publisher is a term which will publish the content to the client that who are subscribed, Subscriber's are the client who can subscribe the notifications.They are two ways you can get the changed data from server by Pulling and Pushing. 

Pulling Method :
                Pulling is the method , where client will get the data from server after a consecutive interval . For example in a website state the status of cricket match, What they do is Pulling method after a 10 sec browser hit the server and get the latest changes from the server. This method will not suit for all notification because if we are going to notify a Football match what will happen goal will put by each team after a half an hour sometimes more than one hour. For this scenario consider each and every 10 seconds if browser hit the server resources cost increases and makes server slow to perform. how to avoid this we can make a Pushing method

Pushing Method : 
              Pushing Method, In this method server will push the change data to the all clients which are connected  and subscribed the notifications.

To Implement the Publisher and Subscriber model we are going to use a WCF with an example of Cricket Match.

Example : Consider a Cricket match going to held we need a notification from the Server with following conditions

1.   Wicket
2.   Five Over Once 
3.   Fifty Runs Once

The beauty of this example we are going to create a single instance for same Client Request even though he request for many times we uses the same single instance that are created before.[singleton service]

1. At the which stage uses click notification , it starts notify the user to notify the update to client.
2. Three options we have on which type we have to notify on every wicket it will notify if the subscriber subscribe the activate.
3. If we close the client and again open the client give the request of notification it will notifies the latest update.
4. wsDualHttpBinding which makes the dual communication from server to client for binding.

Client open and click the following three buttons and get the notifies.





Close the Client and again the launch it and click the notifies button , you can see the latest update is notifies.


See the second screen that from the 8th wicket it s get notified.

Service Code :

Contract :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace CricInfoService
{
    public enum NotifyMode
    {
        Wicket,
        Over,
        FiveOverOnce,
        Runs,
        FiftyRunsOnce
    }

    [ServiceContract(CallbackContract=typeof(IClientCallback))]
    interface ICricketService
    {
        [OperationContract]
        bool GetNotification(NotifyMode mode,string username);

        [OperationContract(IsOneWay=true)]
        void GetNotify(NotifyMode mode, string username);
    }

    public interface IClientCallback
    {      
        [OperationContract(IsOneWay=true)]
        void AsyncNotifyMessage(string message);
    }

}


 Service : InstanceContextMode is single which specifies the singleton

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace CricInfoService
{
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
    public class CricketService:ICricketService
    {
        private static int _wicket = 0;
        private static int _run = 0;
        private static double _over = 0;
        static Random rand = new Random();

        static int Wicket
        {
            set {
                if (!value.Equals(_wicket))
                {
                    _wicket = value;
                    SendNotifyToClient(NotifyMode.Wicket);
                }
            }
            get { return _wicket; }
        }

        static int Run
        {
            set {

                if (!value.Equals(_run))
                {
                    _run = value;
                    if (_run % 50 == 0 )
                    {
                        SendNotifyToClient(NotifyMode.FiftyRunsOnce);
                    }
                 
                }           
            }
            get { return _run; }
        }

        static double Over
        {
            set
            {
                if (!value.Equals(_over))
                {
                    _over = value;

                    int whole =Convert.ToInt32(Math.Truncate(_over));
                       
                    if(_over - whole >= 0.6)
                    {
                        _over = Math.Ceiling(_over);
                    }
                                                
                    if (_over % 5 == 0)
                    {
                        SendNotifyToClient(NotifyMode.FiveOverOnce);
                    }
                }
            }
            get { return _over; }
        }

        public class CricketData
        {
            public  OperationContext CricketContext{set;get;}

            public NotifyMode Mode {set;get;}

            public string UserName {set;get;}           

        }

        static List<CricketData> notifylist = null;

        public CricketService()
        {
            notifylist = new List<CricketData>();
            System.Threading.Thread th = new System.Threading.Thread(Publisher);
            th.Start();
        }

        public bool GetNotification(NotifyMode mode, string username)
        {
            try
            {
                if (mode == NotifyMode.Wicket || mode == NotifyMode.FiveOverOnce || mode == NotifyMode.FiftyRunsOnce)
                {
                    notifylist.Add(new CricketData()
                    {
                        CricketContext= OperationContext.Current,
                        Mode=mode,
                        UserName=username
                    });
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }

        public void GetNotify(NotifyMode mode, string username)
        {
            try
            {
                if (mode == NotifyMode.Wicket || mode == NotifyMode.FiveOverOnce || mode ==                                NotifyMode.FiftyRunsOnce)
                {
                    notifylist.Add(new CricketData()
                    {
                        CricketContext = OperationContext.Current,
                        Mode = mode,
                        UserName = username
                    });                   
                }            
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }

        void Publisher()
        {
            DateTime start = DateTime.Now;
            DateTime Modified =DateTime.Now;

           DateTime wt = DateTime.Now.AddMinutes(NotifySecond(NotifyMode.Wicket));           

            while (true)
            {
                int now = DateTime.Now.Minute;

                if(Wicket<=10)
                    if (wt.Minute == now)
                    {
                        Wicket++;                       
                        wt = wt.AddMinutes(NotifySecond(NotifyMode.Wicket));
                    }
                    else
                    {
                        if((DateTime.Now - Modified).Seconds > 6)
                        {
                            Over += 0.1;
                            Run += 1;
                            Modified = DateTime.Now;
                        }                      
                    }              

                if (Wicket > 10)                                   
                    break;
            }
        }

        private static void SendNotifyToClient(NotifyMode mode)
        {
            for (int i = 0; i < notifylist.Count; i++)
            {
                CricketData data = notifylist[i];                            
                if (data.Mode == mode)
                {
                    Send(data);
                }               
            }                           
        }

        private static void Send(CricketData data)
        {
            int f = NotifySecond(data.Mode);           
            IClientCallback client = 
                       data.CricketContext.GetCallbackChannel<IClientCallback>();
            String message = string.Format("{1}/{0} : Runs/Wickets {2} Overs", Wicket, 
                       Run, Over);
            try
            {
                client.AsyncNotifyMessage(message);
            }
            catch
            {

            }           
        }

        static int NotifySecond(NotifyMode mode)
        {
            if (mode == NotifyMode.Wicket)
            {
                return 1;
            }
            else if (mode == NotifyMode.FiveOverOnce)
            {
                return  2;
            }
            else if (mode == NotifyMode.FiftyRunsOnce)
            {
                 return  3;
            }
            return 0;    
        }

    }
}


 Web Config:
<system.serviceModel>
    <bindings>
      <wsDualHttpBinding>
        <binding name="Bind" bypassProxyOnLocal="true" useDefaultWebProxy="true" />
      </wsDualHttpBinding>
    </bindings>
    <services>     
      <service behaviorConfiguration="returnFaults" name="CricInfoService.CricketService">
        <endpoint address="" binding="wsDualHttpBinding" bindingConfiguration="Bind"                            contract="CricInfoService.ICricketService" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8732/CricInfoService/Cric/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="returnFaults">        
          <serviceMetadata httpGetEnabled="True"/>        
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>


host the WCF service : Hosting WCF Service


Client Code :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace CricClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            SubscriberHandler subscribeclient1 = new SubscriberHandler(CricService.NotifyMode.Wicket, "Rajesh",listBox1);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            SubscriberHandler subscribeClient2 = new SubscriberHandler(CricService.NotifyMode.FiveOverOnce, "suresh", listBox2);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            SubscriberHandler subscribeClient3 = new SubscriberHandler(CricService.NotifyMode.FiftyRunsOnce, "Ram", listBox3);
        }
    }

    class SubscriberHandler : CricService.ICricketServiceCallback
    {
        ListBox lstobj = null;

        public SubscriberHandler(CricService.NotifyMode mode, string name,ListBox obj)
        {
            CricService.CricketServiceClient client = new CricService.CricketServiceClient(new System.ServiceModel.InstanceContext(this));
            lstobj = obj;
            bool status = client.GetNotification(mode, name);
            MessageBox.Show("Cricket Notification Activated in "+ mode.ToString() + " Mode : " + status);
        }

        public void AsyncNotifyMessage(string message)
        {
            lstobj.Items.Add(message);
        }
    }

}



From the above code You can see the SubscriberHandler which will get the instance of each client and send the instance to the service and get the result from the server then server starts the notification from server to client.

From this article you can see the publisher and subscriber model creation from WCF using WsDualHttpBinding.

No comments:

Post a Comment