Click here to Skip to main content
Click here to Skip to main content

Windows Services in Action II

, 28 Dec 2007
Rate this:
Please Sign up or sign in to vote.
This article demonstrates an example of uses of Windows services

Introduction

This article demonstrates a real-world solution. It is my second article explaining Windows Services. If you are not familiar with Windows services on the .NET Framework, you can read my first article, "Windows Services in Action I".

This service will track the hours of a day. It will read the database if the time matches the hour specified in the config file. It will send an e-mail if there is(are) matching date(s).

Background

In this article, you can find many details of coding like reading from config.file, reading from a database, using a timer control, and sending an e-mail in HTML format.

Using the Code

Creating Event Logs

Having an event log in hand is very useful to track our service. So first, let’s create one.

(If you want to make life easier, you can download code from the previous article now. There is already an Eventlog control there.)

It can be dragged-and-dropped from the toolbox into SimpleService.cs (Design mode).

Add codes to create an Eventlog control and its detail. After that, you will have the code block below:

public SimpleService()
{
      InitializeComponent();

      // Initialize eventLogSimple 
      if (!System.Diagnostics.EventLog.SourceExists("SimpleSource")) 
              System.Diagnostics.EventLog.CreateEventSource("SimpleSource", "SimpleLog");
      // SimpleSource will appear as a column in eventviewer.
      eventLogSimple.Source = "SimpleSource";
      // SimpleLog will appear as an event folder.
      eventLogSimple.Log = "SimpleLog";
}

Configuration File

Because there isn't a regular UI, we can use a config file to pass any parameters via the config file. So you can simply add a config file by right-clicking the Project in the Solution Explorer Visual Studio 2005. Click Add, New Item and Application Configuration File, then click OK. After that, you will see the app.config file in your project section. Double click to open it and add the following lines in the <appSettings> section:

<appSettings>
<!-- example value : key="Hour" value="09:00"-->
<add key="Hour" value="10:00"/>
</appSettings>

This means our service will read the data and send emails at 10:00. (I am assuming the time settings are based on 0-24-hours.)

Reading Config File

Let's do this job in a simplistic way. At first, we must add the System.Configuration library adding the line below:

using System.Configuration; 

Then let’s create a function reading from the config file. The function looks like below:

private string ReadConfigFile()
{
     // Create an AppSettingReader object.
     System.Configuration.AppSettingsReader appsreader 
       =new AppSettingsReader();
           
     String value = String.Empty;
     // Get the value Hour from config file.
     value = (String)appsreader.GetValue("Hour", value.GetType());
     // Return it.
     return value.ToString();
}

Reading Data

We can use an Access table named bd.mdb and use OldeDb Provider of the .NET Framework. So we must add using System.Data.OleDb; to the top of SimpleService.cs. We must also create connection string, and query in a while loop and send mail to the person(s) who was(were) born on the day. Sending mail is achieved by another function which is explained shortly.

Here is the code block:

private bool ReadDataFromDB()
{
    string sPName = "";
    string sPSurname = "";
    string sPEmail = "";

    //  What are the day and month today?
    string strMonth = DateTime.Now.Month.ToString();
    string strDay = DateTime.Now.Day.ToString();

    //string strAppPath = System.IO.Directory.GetCurrentDirectory();

    // Create query string which selects Last names, 
    // Names and Emails if the day and month match.
    string sQuery = "Select * from BirthDays where Days='" + 
        strDay + "' and Months='" + strMonth + "';";
    string sConnString = @"Provider=Microsoft.Jet.OLEDB.4.0;
    Data Source=c:\bd.mdb";

    // Write the stage and the brand new query string to the log.
    eventLogSimple.WriteEntry("ReadDataFromDB() called...");
    eventLogSimple.WriteEntry(sQuery);

    // Create DB objects.
    // Assuming that bd.mdb found on c: driver root : c:\bd.mdb
    OleDbConnection DBConn = new OleDbConnection(sConnString);
    OleDbCommand DBComm = new OleDbCommand(sQuery);
    DBComm.CommandType = CommandType.Text;
    DBComm.Connection = DBConn;

    // let's do DB jobs in a try.
    try
    {
        eventLogSimple.WriteEntry("In try...");
        DBConn.Open();
        OleDbDataReader DBReader = DBComm.ExecuteReader();               
        while (DBReader.Read())
        {
            // Write the stage to the log.
            eventLogSimple.WriteEntry("In while...");
        
            sPName = DBReader.GetValue(2).ToString();
            sPSurname = DBReader.GetValue(1).ToString();
            sPEmail = DBReader.GetValue(5).ToString();
        
            SendMailToStaff(sPEmail, sPName + " " + sPSurname);
        
            SendMailToWebAdmin("admin@company.com", 
                "Birthday service sent e-mail to: "+ sPName + " " + sPSurname);

            // Write the job done to the log.
            eventLogSimple.WriteEntry
                ("E-mail: " + DBReader.GetValue(5).ToString() 
                + " - Staff Name: "+sPName + " " + sPSurname);                   
        }
    }
    catch
    {
        // Write if there is an error to the log.
        eventLogSimple.WriteEntry("An error has occurred!");              
    }
    finally
    {
        // Close connection
        DBConn.Close();
    }
    return true;
}

Creating a Timer

Now we need a timer which will decide when to act:

private System.Timers.Timer mytimer = null;

And then we must create a timer object in the OnStart. It will look like below:

protected override void OnStart(string[] args)
{
    // Write "started.." to the log file.
    eventLogSimple.WriteEntry("Simple service started!");
    
    // Get time to send from config file.
    sTimeToSend = ReadConfigFile();
    
    // Write "time to send" to the log file.
    eventLogSimple.WriteEntry("Time to send: " + sTimeToSend);

    // Create timer object and set timer tick to an hour
    MyTimer = new System.Timers.Timer(3600000);
        
    MyTimer.Elapsed += new System.Timers.ElapsedEventHandler
                        (this.ServiceTimer_Tick);
    MyTimer.Enabled = true;
}

Then, let's create a Tick event:

private void ServiceTimer_Tick(object sender, System.Timers.ElapsedEventArgs e)
{
    MyTimer.Enabled = false;

    string sCurrentHour = DateTime.Now.Hour.ToString() + ":00";
    DateTime dCurrentHour = Convert.ToDateTime(sCurrentHour);
    DateTime dTimeToSend = Convert.ToDateTime(sTimeToSend);
    int iComparison = DateTime.Compare(dTimeToSend, dCurrentHour);
    if (iComparison == 0)
        ReadDataFromDB();

    MyTimer.Enabled = true;
}

Sending E-mails

To send mail, we will use the System.Net.Mail; library so we must add to the top again:

using System.Net.Mail;

The service will send an informative email to the Web admin.

private bool SendMailToWebAdmin(string sTo, string sText)
{
    SmtpClient SClient = new SmtpClient();
    System.Net.Mail.MailMessage msgMail = new System.Net.Mail.MailMessage();
    // Most probably the SClient.Host will vary for you. 
    // So you must write your own.
    SClient.Host = "10.1.1.28";
    SClient.Port = 25;
    MailAddress strFrom = new MailAddress("xyx@xyzmail.com");

    string strTo = sTo;
    string strSubject = "Corporate Portal Service - 
    Birthday Congratulation - (Monitoring) ";
    string strEmailBody = sText;
            
    msgMail.Body = strEmailBody;
    msgMail.Subject = strSubject;
    msgMail.To.Add(strTo);
    msgMail.From = strFrom;
    msgMail.IsBodyHtml = true;

    if (strTo.Trim() != "")
    {
        try
        {
            SClient.Send(msgMail);
            eventLogSimple.WriteEntry("Sent");
            return true;
        }
        catch
        {
            eventLogSimple.WriteEntry("Failed");
            return false;
        }
    }
    return false;
}

Mails that we are sending to people is achieved by another function which sends HTML content. Unfortunately, I could not place HTML here. I usually send a very colourful page.

private bool SendMailToStaff(string sTo, string sName)
{
    SmtpClient SClient = new SmtpClient();
    System.Net.Mail.MailMessage msgMail = new System.Net.Mail.MailMessage();
    // Most probably the SClient.Host will vary for you. 
    // So you must write your own.
    SClient.Host = "10.1.1.28";
    SClient.Port = 25;
    MailAddress strFrom = new MailAddress("xyx@xyzmail.com");

    string strTo = sTo;
    string strSubject = "Happy Birthday "+sName+"!";
    string strEmailBody = @"HTML STRING COMES HERE";

    msgMail.Body = strEmailBody;
    msgMail.Subject = strSubject;
    msgMail.To.Add(strTo);
    msgMail.From = strFrom;
    msgMail.IsBodyHtml = true;

    if (strTo.Trim() != "")
    {
        try
        {
            SClient.Send(msgMail);
            eventLogSimple.WriteEntry("Sent");
            return true;
        }
        catch
        {
            eventLogSimple.WriteEntry("Failed");
            return false;
        }
    }
    return false;
}

Points of Interest

I think using services is the best choice in our case. If you think that I am wrong, please let me know.

History

  • 2007-12-28: This is the 4th release of the service which has been running for 2 years.

License

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

About the Author

Umut ŞİMŞEK
Software Developer (Senior)
Turkey Turkey
Started writing code in 1988. There were GW Basic, Turbo Pascal, Turbo C under DOS.
While studentship there were Assembly, C++, digital electronics, microprocessors..in the scene as new things. Then next versions, next generations like Visual Basic, Delphi, C++ Builder, next platforms like Windows, Win32, Linux. Last years many projects took place using various tech and under various platforms. New technologies and IDEs like Delphi 2005, Visual Studio 2003, 2005, C#, ASP.NET, ADO.NET, Metodologies and Tools like UML, Starteam..

Comments and Discussions

 
GeneralThanks and Regard PinmemberCHARTVETTI28-Jun-13 1:34 
Questiontimer control in windows services Pinmemberhasangoto27-Mar-13 23:12 
Questionhow to use windows service in another project? PinmemberNarendra Reddy Vajrala29-Jun-09 1:24 
AnswerRe: how to use windows service in another project? PinmemberUmut ŞİMŞEK5-Aug-09 4:53 
GeneralTimer issue Pinmemberalaac#17-May-08 23:35 
GeneralRe: Timer issue PinmemberUmut SIMSEK15-Aug-08 21:25 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 28 Dec 2007
Article Copyright 2007 by Umut ŞİMŞEK
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid