Click here to Skip to main content
12,823,725 members (58,363 online)
Click here to Skip to main content
Add your own
alternative version

Stats

10.5K views
23 bookmarked
Posted 16 May 2013

Build Your Own Scheduler using IObservable<T>

, 16 May 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
This Article will help you to build your own scheduler with the flavour of Observable Design Pattern


Introduction 

This article will help you to build a Scheduler that you can easily attached with your  .Net Application. By using this scheduler you can configure your schedule time  and also manage modules  with minimum afford. Here i will show you how Observer design pattern helps to make a manageable scheduler.

Background   

Before reading this article  all of you must have the basic knowledge about Observer Design Pattern. It Will help a lot and also make this article easy and interesting to you. By the way here is a typical description

"Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically." 

 




Fig : 1.1 Class diagram for observer pattern. 

In short if i want to explain : 

Concrete  Subject inherits Subject  and Observer inherits Concrete Observer.  

if the Concrete Subject Changes it will notify to others  

Who are the others ? 

Others means those who are attached with the Concrete Subject. 

So finally Concrete Subject changes notify the attached modules. 



Using the code  

Guess i need to build a scheduler which will send email, text sms and upload files to ftp server. So from my previous discussion i can say that i need to make a schedule-task (Concrete Subject) whose responsibility( attached) is to send those mails. In .Net 4.0 we have two nice Interfaces 

  1. IObservable<T>
  2. IObserver<T> 

 If you look on those Interfaces you will notice that it almost have the same methods like our subject and observer in fig 1.1.   

IObservable<T>have only one method  

Disposable Subscribe(IObserver<T> observer)  

if compare with our attached method only the return type makes the difference. So we don't need any detach method here . Why ? because it returns a disposable object of subscribe object.  if you still confuse no problem i will explain it later in my discussion. 

 IObserver<T> have three methods  

void OnCompleted()
void OnError(Exception error)
void OnNext(T value)

 OnNext (T value) is our main concern. It works like Update method on Observer fig 1.1. 

One thing really surprise me where is the Notify of the IObservable<T> ? Ok , Lets back to  our scheduler jobs.

So we need a class for implementing the IObservable<T>.  Below is the class 

public class Observable<T> : IObservable<T>
    {
        List<IObserver<T>> observers = new List<IObserver<T>>();
 
        public Observable()
        {
           
            observers = new List<IObserver<T>>();
        }
 
        protected void Notify(T obj)
        {
            foreach (IObserver<T> observer in observers)
            {
                observer.OnNext(obj);
            }
        }
 
        public IDisposable Subscribe(IObserver<T> observer)
        {
            if (!observers.Contains(observer))
            {
                observers.Add(observer);
            }
 
            return new Unsubscriber(observers, observer);
        }
 
 
        private class Unsubscriber : IDisposable
        {
            private List<IObserver<T>> observers;
            private IObserver<T> observer;
 
            public Unsubscriber(List<IObserver<T>> observers, IObserver<T> observer)
            {
                this.observers = observers;
                this.observer = observer;
            }
 
            public void Dispose()
            {
                if (observer != null && observers.Contains(observer))
                {
                    observers.Remove(observer);
                }
            }
        }
    }

 So we have the generics class with the Notify method . Here you can see how you can get the IDisposable after subscribe. Now we can consider the Observable<T> class as Subject . Now we need  our concrete subject. 

public class SchedulerTask : Observable<SchedulerTask>
    {
        bool _switchOn;
 
 
        public bool SwitchOn
        {
            get
            {
                return _switchOn;
            }
            set
            {
                _switchOn = value;
                if (_switchOn)
                {
 
                    Notify(this);
                }
            }
        }
 
 
        public SchedulerTask()
        {
            
        }
    }

So our SchedulerTask class designed on the way  that if  property value SwitchOn sets true it will call the base classes Notify method and all the subscribe modules  will be notified.

So for three tasks we need the classes that will process or execute the task.  And the will be notified by the SchedularTask class when update happen. To receive the notification (OnNext(T) they need to implement IObserver<T>.  

This is for MailSend  

public class SendNotificationMail : IObserver<SchedulerTask>
    {
        public SendNotificationMail()
        {
 
        }
 
        public void OnCompleted()
        {
            throw new NotImplementedException();
        }
 
        public void OnError(Exception error)
        {
            throw new NotImplementedException();
        }
 
        public void OnNext(SchedulerTask value)
        {
            //Task that needs to be done on schedule time
            // ProcessSendNotificationMailMails(value);
        }        
    }

This is for TextSMS

public class SendTextMessaage : IObserver<SchedulerTask>
    {
        public SendTextMessaage()
        {
 
        }
        public void OnCompleted()
        {
            throw new NotImplementedException();
        }
 
        public void OnError(Exception error)
        {
            throw new NotImplementedException();
        }
 
        public void OnNext(SchedulerTask value)
        {
            //Task that needs to be done on schedule time
            // ProcessSendTextMessaage(value);           
        }
        
    }   

This is for Upload file

public class UpLoadFileFromFtp :IObserver<SchedulerTask>
    {
        public UpLoadFileFromFtp()
        {
 
        }
        public void OnCompleted()
        {
            throw new NotImplementedException();
        }
 
        public void OnError(Exception error)
        {
            throw new NotImplementedException();
        }
 
        public void OnNext(SchedulerTask value)
        {
            //Task that needs to be done on schedule time
            // ProcessUpLoadFileFromFtp(value);
        }
    }

Here i am not showing the full implementation for the send mail sms or fileupload. So we have all of the modules . But still one important thing left . Did you notice that ? No, the subscription or attachment of the ScheduerTask with SendNotificationMail , SendTextMessaage and UpLoadFileFromFtp.

To manage those classes we need a manager class  right which will integrate those with each other.

public class ManageScheduleTasks
   {
       SchedulerTask objScheduler;
       Action<bool> TriggerScheduler;

       public ManageScheduleTasks()
       {
           Register();
       }
       protected  void Register()
       {
           objScheduler = new SchedulerTask();
           GetSubsCribtionList().ForEach(p =>
           {
               objScheduler.Subscribe(p);

           });
           TriggerScheduler = InvokeScheduler;
       }

       protected List<IObserver<SchedulerTask>> GetSubsCribtionList()
       {
           return new List<IObserver<SchedulerTask>>()
           {
               new SendNotificationMail(),
               new SendTextMessaage(),
               new UpLoadFileFromFtp()
           };

       }
       public void StartScheduler()
       {
           double dblmilisec = ConfigurationManager.AppSettings["scheduleTimeinMinute"] != null ?
               Convert.ToDouble(ConfigurationManager.AppSettings["scheduleTimeinMinute"])
               * 60000 : -1;
           System.Timers.Timer t = new System.Timers.Timer();
           t.Elapsed += new System.Timers.ElapsedEventHandler(IsTimeToStartScheduler);
           t.Interval = dblmilisec;
           t.Enabled = true;
           t.AutoReset = true;
           t.Start();
       }

       private void IsTimeToStartScheduler(object sender, System.Timers.ElapsedEventArgs e)
       {
           var start = ConfigurationManager.AppSettings["scheduleStartTime"] != null ?
               Convert.ToString(ConfigurationManager.AppSettings["scheduleStartTime"]) : "";
           var triger = start.Equals(DateTime.Now.ToString("hh:mm tt"));
           TriggerScheduler(triger);
       }
       private void InvokeScheduler(bool isStartTime)
       {
           objScheduler.SwitchOn = isStartTime;
       }
   }

Don't worry by seeing the manager class. I will explain each and every method setp by step.

First of all look at the constructor of the  ManageScheduleTasks class. what it does?  It calls the Register method. The Register method actually subscribe all the modules (by calling the functionGetSubsCribtionList ) that will be notified by the SchedulerTask. TriggerScheduler is just an Action<bool> will explain it too. So far so good Right. 

public ManageScheduleTasks()
        {
            Register();
        }
        protected  void Register()
        {            
            objScheduler = new SchedulerTask();
            GetSubsCribtionList().ForEach(p =>
            {
                objScheduler.Subscribe(p); // Subscribe all the module

            });
            TriggerScheduler = InvoveScheduler;
        }
 
        protected List<IObserver<SchedulerTask>> GetSubsCribtionList()
        {
            return new List<IObserver<SchedulerTask>>()
            {                  
                new SendNotificationMail(),  // Return the list of modules
                new SendTextMessaage(),     // that will be notified during
                new UpLoadFileFromFtp()    //Scheduler process  running                         
            };
 
        }

Now question might comes on your mind that what is the use of other three methods StartScheduler,IsTimeToStartScheduler,InvoveScheduler ? Below is the answer

StartScheduer : This method introduces a timer that calls a method IsTimeToStartScheduler after every 1 minute . The interval value comes from the web.config scheduleTimeinMinute . Here i Set 1 .
<appSettings>
    <add  key="scheduleTimeinMinute" value="1"/>
    <add   key="scheduleStartTime" value="01:00 AM"/>
  </appSettings>
public void StartScheduler()
        {
            double dblmilisec = ConfigurationManager.AppSettings["scheduleTimeinMinute"] != null ?
                Convert.ToDouble(ConfigurationManager.AppSettings["scheduleTimeinMinute"]) 
                * 60000 : -1;
            System.Timers.Timer t = new System.Timers.Timer();
            t.Elapsed += new System.Timers.ElapsedEventHandler(IsTimeToStartScheduler);
            t.Interval = dblmilisec;
            t.Enabled = true;
            t.AutoReset = true;
            t.Start();
        }

IsTimeToStartScheduler :  This method will get the exact time to start the scheduler from the web.config scheduleStartTime and check is the time to start scheduler. At 01:00AM It will set the value of var trigger is true .01:00AM comes from my web.configschedulerStartTime .   

 <appSettings> 
<add key="scheduleTimeinMinute" value="1"/> 
<add key="scheduleStartTime" value="01:00 AM"/> 
</appSettings>  

if the value of var trigger is true then the scheduler starts. Confuse , how it will start ? Below is the explanation.  

private void IsTimeToStartScheduler(object sender, System.Timers.ElapsedEventArgs e)
       {
           var start = ConfigurationManager.AppSettings["scheduleStartTime"] != null ?
               Convert.ToString(ConfigurationManager.AppSettings["scheduleStartTime"]) : "";
           var triger = start.Equals(DateTime.Now.ToString("hh:mm tt"));
           TriggerScheduler(triger);
       }

So as i told you earlier TriggerScheduler is an action that points to the InvokeScheduler   and it is actually setting the SwitchOn value. So you remember the property when it calls the notify ? When it sets value to true.  

private void InvoveScheduler(bool isStartTime)
    {
        objScheduler.SwitchOn = isStartTime;
    }
public bool SwitchOn
       {
           get
           {
               return _switchOn;
           }
           set
           {
               _switchOn = value;
               if (_switchOn)
               {

                   Notify(this);
               }
           }
       }  

Points of Interest 

So, how we hookup my  ManageScheduleTasks class with Http . Here is the tricks  use your Global.asax.cs  class put the below code  on Application_Start

public class Global : System.Web.HttpApplication
    {
 
        protected void Application_Start(object sender, EventArgs e)
        {
            var manageSchdule = new ManageScheduleTasks();
            manageSchdule.StartScheduler();
        }        
    }

Thats it. your scheduler is now attached with your application.

This Scheduler will call on a specific time of the day . But if you want to call after every  (1,2.3...n) minute you just do the following  and change the value of scheduleTimeinMinute to any minute interval  you need.

private void IsTimeToStartScheduler(object sender, System.Timers.ElapsedEventArgs e)
        {
            
            TriggerScheduler(true);
        } 

So we finally developed a scheduler.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Faisal(mfrony)
Bangladesh Bangladesh
I am a Sr.Software Engineer at Brain Station -23. I have 5+ years of work experience in .Net technology. I strongly believe that before software can be reusable it first has to be usable.

My contact info :

mfrony2003@yahoo.com
mfrony2003@hotmail.com

LinkedIn
http://www.linkedin.com/profile/view?id=106671466&trk=tab_pro

You may also be interested in...

Pro
Pro

Comments and Discussions

 
QuestionCan you provide the source code? Pin
Sudhir Dutt Rawat10-Nov-14 7:57
memberSudhir Dutt Rawat10-Nov-14 7:57 
QuestionAny source code about? Pin
Fabio Malpezzi13-Jan-14 22:29
memberFabio Malpezzi13-Jan-14 22:29 
AnswerRe: Any source code about? Pin
Faisal(mfrony)15-Jan-14 5:02
memberFaisal(mfrony)15-Jan-14 5:02 
GeneralRe: Any source code about? Pin
Abhishek Pant9-Jun-14 6:04
professionalAbhishek Pant9-Jun-14 6:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.170308.1 | Last Updated 16 May 2013
Article Copyright 2013 by Faisal(mfrony)
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid