Sunday, December 13, 2009

Running a Periodic Process in .NET using a Windows Service

The need does arise from time to time (literally) to process some repeated task in .NET. This question comes up a lot and about the best way of solving this problem. Should I poll repeatedly? Do I use a timer? What kind of timer should I use? etc...

Usually this question comes up when the need arises to do any of the following examples: checking for new information, reporting, sending emails, updating content on a screen, maintenance, and the examples go on and on.

I prefer to relegate this type of task to a Windows Service. The service can be created using Visual Studio .NET and then installed on your machine or server. The service is always running (once started) and provides a good mechanism for preforming repeated background tasks like periodic execution.

After doing research on this topic myself, I have found the best way to have a process run on a set time interval is to use a 'ThreadPool.RegisterWaitForSingleObject' from the System.Threading namespace. As from the
MSDN on this method: "Registers a delegate to wait for a WaitHandle, specifying an integer for the time-out in milliseconds."

The 'RegisterWaitForSingleObject' method registers a delegate to wait for a WaitHandle, specifying a timeout. It allows this service to tell the thread pool, "Hey, could you call me when this object is signalled or the timeout has elapsed? Thanks." The method queues the specified delegate to the thread pool (The thread pool uses background threads). A worker thread will execute the delegate when one of the following occurs:


-The specified object is in the signaled state.
-The time-out interval elapses.

This method will repeatedly call the delegate each time the timespan value has elapsed, or until the 'Unregister' method has been called. The callback method registered can do anything you need. The actual method will probably be local to the service, but from there you could make a call to a .dll, WCF or .asmx service, etc. to reuse existing functionality that may already exist. You just need the Windows Service to the the work of waking up every so often to do some work.

You can implement 1:many of these delegates to run as few or as many repeated tasks from within a Windows Service. I must give credit to the following Blog entry which really helped get me started with using this method: Periodic Execution in .NET <<--Code

The blog link above has a terrific easy to follow code example with explanations of implementing the RegisterWaitForSingleObject within a Windows Service, so I will not duplicate it here. I will just say that I myself have implemented the code and expanded on it, and can say that this is a great way to handle repeated processing of a task on a set time interval.

And lastly, you might be saying "I don't know how to create and use a Windows Service in .NET!". Well to get you going on that (there are quite easy by the way to get up and running), check out the following site:

Walkthrough: Creating a Windows Service Application in the Component Designer

Saturday, December 12, 2009

How To: Bind an Enum to an ASP.NET DropDownList

Enumerations are a great way to categorize and structure a set of data within your application, and is usually a 'next step' or improvement at times from hardcoding miscellaneous values throughout an application. Some examples of using an enumeration might be for month names, credit card types accepted, colors, season names, file formats, and the examples are endless.

You may find that you need or want to bind that enumeration directly to a control such as an ASP.NET DropDownList. The DropDownList is obviously an easy fit for an enumeration as it uses a key-value pair style of data for its 'Text' and 'Value' attributes which align to an enumeration's member name and initializer attributes.

For all of the following examples, we will work with the following simple enumeration using 'Months of the Year' (yes, it may be possible to get this same info by looping through a DateTime object and adding 1 month to each iteration, but this is just to show a basic example of a simple enumeration type):

Public Enum Months
January = 1
February = 2
March = 3
April = 4
May = 5
June = 6
July = 7
August = 8
September = 9
October = 10
November = 11
December = 12
End Enum

Accomplishing this task can be done in so many ways. One way is to directly bind just the enum member values to a DropDownList without its associated name. This may acceptable in the situation of months in the year where only the actual integer value is needed. This code to bind just the values is displayed below:

'Populate the months dropdown (from Enumeration)
Dim tEnumMonths As Type = GetType(Months)
Me.ddlMonths.DataSource = System.Enum.GetValues(tEnumMonths)
Me.ddlMonths.DataBind()
'Insert blank '0' value at beginning of DropDown
Me.ddlMonths.Items.Insert(0, New ListItem(" "))

However, most of the time you will probably find that you want to bind both the member name and its associated value. This way you can display to the user a description and extract its value server side for storing in a database, processing business rules, etc. In this case we need to transform or port the enumeration data from the enum type into a bindable object type to the ASP.NET DropDownList. There are so many bindable types; a few examples are: DataSet, DataTable, DataView, Array, ArrayList, HashTable, Object Collection (Generics), and many more.

In the following I will focus on (3) additional methods. All will involve calling a Shared function in a 'Utilities' call that is accessible by all of the UI. This type functionality is not specific to any specific object and holds no concise responsibility other than being a 'Helper' function. Therefore these methods are Shared and do not require class instantiation to access.

The 1st method will take the DropDownList in question and the Enum type as parameters and perform all of the work necessary to bind the data. This method is a full on binding method specific to an ASP.NET DropDownList, so in that sense it is quite powerful, but offers not much reuse beyond binding to this control type.

Public Shared Sub BindDDLToEnum(ByVal EnumType As Type, ByVal DropDown As UI.WebControls.DropDownList, ByVal InsertBlankZeroValue As Boolean)

'Get the Name (String) values from the Enum
Dim EnumNames As String() = System.Enum.GetNames(EnumType)

'Get the Values (Integer) from the Enum
Dim EnumValues As Array = System.Enum.GetValues(EnumType)

'If the caller requested a blank entry with a value of 0 entered, do that now.
If InsertBlankZeroValue Then
'Add a space and a '0' value at the beginning
DropDown.Items.Add(New Web.UI.WebControls.ListItem(" ", 0))
End If

'Loop through the Enum values and add the name,value pair to a 'ListItem' object to be directly inserted into the DropDownList
For i As Integer = 0 To EnumNames.Length - 1
DropDown.Items.Add(New Web.UI.WebControls.ListItem(EnumNames(i), Integer.Parse(EnumValues.GetValue(i))))
Next

'If a blank '0' value was entered, make sure it is the default selected item. This is important
'for RangeValidator controls and the like to pick up on and validate against.
If InsertBlankZeroValue Then
DropDown.ClearSelection()
DropDown.Items.FindByValue(0).Selected = True
End If

End Sub

As you can also see above, I chose to add an additional boolean parameter named 'InsertBlankZeroValue'. This value dictates if a blank string with a '0' value is inserted as the 1st element in the DropDownList. This functionality could easily be modified, removed, or even expanded (i.e. take additional parameters specifying default name and value rather than '0' and blank) to suit your individual needs.

Now you may want to make some more abstract methods that transform the Enum into a bindable type, but don't want to bind it immediately to a control. In this case I have made (2) more sample methods that simply take the Enum type and return a key-value pair object. The 1st method returns a HashTable as shown below:

Public Shared Function GetHashTableFromEnum(ByVal EnumType As Type) As Hashtable

'Get the Name (String) values from the Enum
Dim EnumNames As String() = System.Enum.GetNames(EnumType)

'Get the Values (Integer) from the Enum
Dim EnumValues As Array = System.Enum.GetValues(EnumType)

'Declare a HashTable to hold the Enum name,value pairs
Dim ht As New Hashtable()

'Loop through all of the name,value pairs in the Enum and add them as new elements to the HashTable
For i As Integer = 0 To EnumNames.Length - 1
ht.Add(EnumNames(i), Integer.Parse(EnumValues.GetValue(i)))
Next

Return ht

End Function

The main issue you will note about the method above is that the HashTable returned will indeed have the enum values in a key-value format but they will not be in the order that they were within the Enum. Typically this is an unwanted result. This class could be expanded to implement an ICompare interface and expose a sorting routine to then sort the HashTable values. However, other object types will give us this functionality with built in ability.

The last type I wrote a Utilities method for that solves the sorting issue is by returning a 'DataTable' object from the Enum type passed in as an argument. Once the DataTable is created by making a table with (2) columns named "key" and "value", we can create a DataView from it using the sort we specify and then return a DataTable type back from the DataView. The code for this is shown below:

Public Shared Function GetDataTableFromEnum(ByVal EnumType As Type) As DataTable

'Get the Name (String) values from the Enum
Dim EnumNames As String() = System.Enum.GetNames(EnumType)

'Get the Values (Integer) from the Enum
Dim EnumValues As Array = System.Enum.GetValues(EnumType)

'Declare a new DataTable with column names "key" and "value"
Dim dt As New DataTable()
dt.Columns.Add("key", GetType(String))
dt.Columns.Add("value", GetType(Integer))

'Loop through all of the name,value pairs in the Enum and add them as new rows to the DataTable
For i As Integer = 0 To EnumNames.Length - 1
Dim dr As DataRow = dt.NewRow
dr("key") = EnumNames(i)
dr("value") = Integer.Parse(EnumValues.GetValue(i))
dt.Rows.Add(dr)
Next

'Sort the DataTable by the value column
Dim dv As DataView = dt.DefaultView
dv.Sort = "value asc"

'Apply the sorted DataView back to the DataTable to be returned
dt = dv.ToTable()

Return dt

End Function

Once again it is important to note that this method is just a base example and could be customized easily to fit your needs. As you can see above, the method automatically sorts based on the "value" column in ascending order. You could add parameters to the method that could dictate the sort. And you could also change this method and just have the DataView returned rather than extracting a DataTable back out of it. Both types can be used as the DataSource for a control like an ASP.NET DropDownList.

Below is the code used to make the call to the Utilities class and have it bound to our 'Months' enumeration.

'Option 1: Bind the DropDownList immdeatly to the Enum type
Utilities.BindDDLToEnum(GetType(Months), Me.ddlMonths, True)

'Option 2: Get a HastTable back from the Enum, and use it however needed:
Dim MyHt As New Hashtable()
MyHt = Utilities.GetHashTableFromEnum(GetType(Months))

'Option 3: Get a DataTable back and then bind on the columns named "key" value"
Dim MyDt As New DataTable
MyDt = Utilities.GetDataTableFromEnum(GetType(Months))
'Set the Text and Value properties which correspond to the "value" and "key" elements
'of the DataTable object created and populated above
Me.ddlMonths.DataTextField = "key"
Me.ddlMonths.DataValueField = "value"
'Set the DataSource Bind the DataView to the passed in DDL control
Me.ddlMonths.DataSource = MyDt
Me.ddlMonths.DataBind()

Lastly is a picture of the bound ASP.NET DropDownList:

The main purpose of this was just to get you as the developer started when needing to bind an Enum to a control like an ASP.NET DropDownList. You can easily expand or modify any of the methods to suit your needs providing the most streamlined use and reusability for your application.