Wednesday, November 2, 2011

Blank ASP.NET Page

ASP.NET page getting rendered as blank with empty source

This week, I encountered a strange problem with one of my ASP.Net websites. This website is hosted on multiple servers. Upon clicking a link on the home page, the web application takes me to a page. The scenario was working fine on all servers except one. On this particular server, when I tried to browse this page, I would get a blank page. The first thing I checked was the source of the page. The page had the following source:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content="text/html; charset=windows-1252" http-equiv=Content-Type></HEAD>
<BODY></BODY></HTML>


My first guess was that either javascript or html was breaking which was preventing the page from rendering. So, I turned on script debugging in IE. To my surprise, I got no scripting error. The Google search did not yeild anything useful either. The problem was hard to debug because the code was working fine on my local machine and all other servers. I decided to look into the code behind for potential problems. There I found out that in my global.asax file, exception level is handled at application level. In case of any page-level exception, we were propagating the exception to the application level and were displaying a generic error page with exception details. Please note that this problematic page was recently added to our website. Instead of adding it to the top level directory, we added it to a subfolder. So, for this page, the generic error page was present one level up in the folder hierarchy and hence, was unable to locate it. I copied the generic error page to the subfolder and bingo, this time I saw the following generic error page instead of seeing the blank page:

SQL Server does not exist or access denied.

Therefore, the blank page problem was due to IIS unable to locate the generic error page, since it was not there in the subfolder. Hence, the server was transfering itself to a a blank page instead of redirecting me. Once, I copied the generic error page in the subfolder, it was able to locate the generic error page and hence, showed me the actual exception.

So, I resolved one problem but fell into another one. For some reason the server was not able to connect to the database. To resolve this issue, I tried the following steps:

1. Checked the connection string- it was good
2. Increased connection time-out- still not able to establish connection
3. Pinged database server from application server- ping was successful
4. Telnet database server from application server- telnet failed
5. Turned off the firewall on application server for testing- still not able to telnet to the database server
6. Telnet database server from another application server (having no problem)- telnet was successful

The above steps concluded that even though the firewall was turned off on the application server, I was not able to connect to the database server. The only thing then left to check was firewall settings on the database server. It turned out that the firewall on database server was allowing connections with a set of allowed incoming IPs. Upon adding this application server to the list of allowed servers, the application was able to connect and the page started to render fine.

Cheers!
JS

Thursday, October 13, 2011

Checked False Disabled HTML CheckBox

Checked property is false for disabled html checkbox

If an html checkbox is disabled through javascript and the form is submitted, the checked property of the disabled checkbox will always come up as false. This happens because when a an html control is disabled, it is not included in the post back. Hence, the checked property will always be false.

One potential solution to this problem is to enable the checkbox through javascript when submitting the form. Usually, this happens when some javascript is called to validate the form. We can enable back the checkbox at this point so that the actual value of checked property can be included in the postback.

Another possible solution is to replace html checkbox with ASP .Net checkbox control. You can choose one of these solutions as per your situation.
 
Cheers!
JS

Friday, August 5, 2011

Implementing the Mode Handler of Self-Service Application using Finite State Machine

Implementing ATM/CDM/Kiosk states (Suprvisory, OOS, Offline, In-Service) in C#

Hi,

Some of you will find this post extremely useful, while, some of you will find it completely irrelevant. There is a good reason for both opinions. Self-Service industry is a very specialized domain. Unlike ASP .NET and other commonly used technologies, there is very little or no information available on this subject. Today, I am going to implement a mode handler of Self-Service application using Finite State Machine. Before doing that, we will first go through the basic concepts of SST, Modes, and Mode Handling. I am assuming in this article that you are well aware of the state design pattern and familiar with finite state machines.


Self-Service Terminals

Self-Service Terminals (SST) are pretty common today and come in different forms. You use an ATM to withdraw cash from banks. Kiosks at movie theaters are used to purchase movie tickets. Similarly, kiosks at airports are used for passenger check-in. These are all instances of Self-Service terminals.


Self-Service Transactions

SSTs offer a wide range of transactions. Though, it is not possible to list down all types of transactions, but the following are the most common SST transactions:

i. Cash Withdrawal
ii. Cash Deposit
iii. Check Deposit
iv. Balance Inquiry
v. Utility Bill Payment
vi. Toll/Fine Payment
vii. Mobile Topup/Recharge
viii. Tickets Purchasing
ix. Job Applications
x. Information Viewing


Self-Service Application Modes

Self-Service terminals such as ATMs, CDMs, and Kiosks operate in 4 standard modes. These are:

1. Offline

The connectivity of machine to the network is broken. The SST cannot send and receive messages over the network. This mode is called Offline mode.

2. Out-of-Service

An SST may become Out-of-Service (OOS) for various reasons. The two major reasons are software or hardware failure. However, in most of the cases, OOS mode is caused by a hardware problem. Common examples are notes stuck in Bunch-Note Acceptor, checks stuck in Check Processing Module, or Journal Printer out of paper. In most of the cases, the machine cannot recover itself from OOS mode by itself and requires manual human effort. Someone must come and remove the stuck notes/checks or replenish Journal paper.

3. Supervisory

This is the servicing mode of the SST. Terminal is switched to Supervisory mode when hardware repair is performed. Also, when the terminal is out of cash or paper, the replenishment activity can be only performed when the SST is in supervisory mode. Supervisory mode operations are not only restricted to repair and replenishment, but also include closing of the business cycle and balancing.

A hardware switch/button installed usually inside the SST is used to switch the machine to supervisory mode.

4. In-Service

When SST is not in any of the aforementioned modes, then it means it is ready to complete customer’s transactions. Hence, it is in In-Service mode. The following are the requisites for an SST to become In-Service:

a. Terminal is connected to the network and can send and receive messages
b. All critical devices required to complete a transactions are working
c. Supervisory switch is not turned on.


Mode Handler

A Mode Handler is a controller which is responsible to switch SST to appropriate modes based on the current state of the terminal. Mode Handler is the most critical part of any Self-Service application. Any flaw in Mode Handler can cause devastating results. Take the example of Supervisory mode. This mode should be available to machine supervisors/custodians only. If a customer is given access to the supervisory mode, then the customer can perform actions like clearing the business-cycle, dispense notes from the machine, etc. Scenarios like these may cause huge financial losses.


Implementation of Mode Handler through Finite State Machine

Since each mode of the Self-Service terminal represents the state of the machine, therefore, Mode Handler is implemented in the form of finite state machine. We will write a class to model each state of the machine. In this way, we will have 4 classes. We will also write a controller class to implement state switching.

Since, we are just writing the Mode Handler and not the whole Self-Service application, we will demonstrate the working of Mode Handler through a WinForms application. The WinForms application will contain checkboxes. Each checkbox will represent the condition that triggers state switching.

It is also to be noted that a Self-Service applications should always start in OOS mode. This is the safest mode. The Mode Handler should then check all state switching conditions and should switch SST to appropriate mode. Also, for security reasons, In-Service mode should be the last possible state of the machine after going through all state switching conditions. On the contrary, Supervisory mode should be the top priority mode because if a machine supervisor/custodian has pressed the supervisory switch, the Self-Service application should immediately switch to supervisory mode. The only exception is when a transaction is in progress. In this case, the terminal should first finish the transaction and then switch to supervisory mode.

The following is the sample code of a Mode Handler written in C#.

VariablesStore.cs

namespace SST
{
///
/// Summary description for VariablesStore.
///

public class VariablesStore
{ // implementing global store to save state of the machine
// and other variables to use throughout the application
// provides better control and code-maintenance
public static int SupervisoryOn = 0;
public static int Failure = 0;
public static int NetworkFailure = 0;
}
}


SSTModes.cs


namespace SST
{
abstract class Mode
{ // provides template for child mode classes
protected int MyMode = 0;

private int CheckSupervisorSwitchOn()
{ // check if someone pressed supervisory switch
return VariablesStore.SupervisoryOn;
}

private int CheckFailures()
{ // check if a device has failed
return VariablesStore.Failure;
}

private int CheckNetworkConnectivityFailure()
{ // check if network connection is broken
return VariablesStore.NetworkFailure;
}

public int GetNextMode()
{ // perform SST health check and recommend appropriate mode
// highest priority is supervisory switch

// returning modes based on HC
if (CheckSupervisorSwitchOn() == 1)
return 1;

if (CheckFailures() == 1)
return 2;

if (CheckNetworkConnectivityFailure() == 1)
return 3;

return 4;
}

// needs to be implemented in particular modes only
public abstract int ProcessMode();
}

class SupervisoryMode : Mode
{ // models Supervisory mode of SST

public SupervisoryMode()
{ // this is my mode number
MyMode = 1;
}

public override int ProcessMode()
{
// do HC and see it I am a valid mode
int ValidMode = GetNextMode();

// if I am valid mode, I can start my processing
while (ValidMode == MyMode)
{
// supervisory operations start

// supervisory operations end

// I have ended my processing, now check if I can exit
ValidMode = GetNextMode();
}

// return next valid mode for SST
return ValidMode;
}
}

class OOSMode : Mode
{ // models OOS mode of SST
public OOSMode()
{
MyMode = 2;
}

public override int ProcessMode()
{
// do HC and see it I am a valid mode
int ValidMode = GetNextMode();

// if I am valid mode, I can start my processing
while (ValidMode == MyMode)
{
// OOS operations start

// OOS operations end

// I have ended my processing, now check if I can exit
ValidMode = GetNextMode();
}

// return next valid mode for SST
return ValidMode;
}
}

class OfflineMode : Mode
{ // models Offline mode of SST
public OfflineMode()
{
MyMode = 3;
}

public override int ProcessMode()
{
// do HC and see it I am a valid mode
int ValidMode = GetNextMode();

// if I am valid mode, I can start my processing
while (ValidMode == MyMode)
{
// Offline operations start

// Offline operations end

// I have ended my processing, now check if I can exit
ValidMode = GetNextMode();
}

// return next valid mode for SST
return ValidMode;
}
}

class InServiceMode : Mode
{ // models In-Service mode of SST
public InServiceMode()
{
MyMode = 4;
}

public override int ProcessMode()
{
// do HC and see it I am a valid mode
int ValidMode = GetNextMode();

// if I am valid mode, I can start my processing
while (ValidMode == MyMode)
{
// In-Service operations start

// In-Service operations end

// I have ended my processing, now check if I can exit
ValidMode = GetNextMode();
}

// return next valid mode for SST
return ValidMode;
}
}
}


SSTApp.cs


using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
using System.Data;

namespace SST
{
///
/// Summary description for SSTApp.
///

public class SSTApp : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnStart;
private System.Windows.Forms.CheckBox chkSupervisor;
private System.Windows.Forms.CheckBox chkFailure;
private System.Windows.Forms.CheckBox chkConnectivity;
///
/// Required designer variable.
///

private System.ComponentModel.Container components = null;

public SSTApp()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

///
/// Clean up any resources being used.
///

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///

private void InitializeComponent()
{
this.btnStart = new System.Windows.Forms.Button();
this.chkSupervisor = new System.Windows.Forms.CheckBox();
this.chkFailure = new System.Windows.Forms.CheckBox();
this.chkConnectivity = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// btnStart
//
this.btnStart.Location = new System.Drawing.Point(8, 16);
this.btnStart.Name = "btnStart";
this.btnStart.TabIndex = 0;
this.btnStart.Text = "Start";
this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
//
// chkSupervisor
//
this.chkSupervisor.Location = new System.Drawing.Point(8, 64);
this.chkSupervisor.Name = "chkSupervisor";
this.chkSupervisor.Size = new System.Drawing.Size(136, 24);
this.chkSupervisor.TabIndex = 1;
this.chkSupervisor.Text = "Supervisor Switch On";
this.chkSupervisor.CheckedChanged += new System.EventHandler(this.chkSupervisor_CheckedChanged);
//
// chkFailure
//
this.chkFailure.Location = new System.Drawing.Point(8, 96);
this.chkFailure.Name = "chkFailure";
this.chkFailure.TabIndex = 2;
this.chkFailure.Text = "Device Failure";
this.chkFailure.CheckedChanged += new System.EventHandler(this.chkFailure_CheckedChanged);
//
// chkConnectivity
//
this.chkConnectivity.Location = new System.Drawing.Point(8, 128);
this.chkConnectivity.Name = "chkConnectivity";
this.chkConnectivity.Size = new System.Drawing.Size(128, 24);
this.chkConnectivity.TabIndex = 3;
this.chkConnectivity.Text = "Connectivity Failure";
this.chkConnectivity.CheckedChanged += new System.EventHandler(this.chkConnectivity_CheckedChanged);
//
// SSTApp
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(152, 165);
this.Controls.Add(this.chkConnectivity);
this.Controls.Add(this.chkFailure);
this.Controls.Add(this.chkSupervisor);
this.Controls.Add(this.btnStart);
this.Name = "SSTApp";
this.Text = "SSTApp";
this.Load += new System.EventHandler(this.SSTApp_Load);
this.ResumeLayout(false);

}
#endregion

///
/// The main entry point for the application.
///

[STAThread]
static void Main()
{
Application.Run(new SSTApp());
}

private void SSTApp_Load(object sender, System.EventArgs e)
{

}

public void ModeHandler()
{
// be default, SST will start in OOS mode
int CurrentMode = 2;

// init all modes
Mode ThisMode = null;
SupervisoryMode ThisSupervisoryMode = new SupervisoryMode();
OOSMode ThisOOSMode = new OOSMode();
OfflineMode ThisOfflineMode = new OfflineMode();
InServiceMode ThisInServiceMode = new InServiceMode();

while (true)
{
MessageBox.Show("Switching to Mode " + CurrentMode.ToString());

// check which mode to switch to
switch (CurrentMode)
{
case 1:
{ // set Supervisor mode as mode to run
ThisMode = ThisSupervisoryMode;
break;
}
case 2:
{ // set OOS mode as mode to run
ThisMode = ThisOOSMode;
break;
}
case 3:
{ // set Offline mode as mode to run
ThisMode = ThisOfflineMode;
break;
}
default:
{ // If everything is fine,
// set In-service mode as mode to run
ThisMode = ThisInServiceMode;
break;
}
}

// run this mode now
CurrentMode = ThisMode.ProcessMode();

// switch to different mode after 3 secs (not necessary)
Thread.Sleep(3000);
}
}

private void btnStart_Click(object sender, System.EventArgs e)
{ // start mode handler in a separate thread
Thread ModeHandlerThread = new Thread(new ThreadStart(ModeHandler));
ModeHandlerThread.Start();
}

private void chkSupervisor_CheckedChanged(object sender, System.EventArgs e)
{ // simulating through checkbox supervisory switch pressing on the actual SST
if (chkSupervisor.Checked)
VariablesStore.SupervisoryOn = 1;
else
VariablesStore.SupervisoryOn = 0;
}

private void chkFailure_CheckedChanged(object sender, System.EventArgs e)
{ // simulating through checkbox some device failure on the actual SST
if (chkFailure.Checked)
VariablesStore.Failure = 1;
else
VariablesStore.Failure = 0;
}

private void chkConnectivity_CheckedChanged(object sender, System.EventArgs e)
{ // simulating through checkbox network connectivity failure
if (chkConnectivity.Checked)
VariablesStore.NetworkFailure = 1;
else
VariablesStore.NetworkFailure = 0;
}
}
}


UI Details

When you launch the application, you will see the main form. You need to click on Start button to start the Mode Handler. Use checkboxes to simulate state switching conditions. Whenever the application switches state, it will display a message box with state number. The following are the state numbers:

Supervisory = 1
OOS = 2
Offline = 3
In-Service = 4



I have included a 3 second delay in state switching to make it easier to observe.

If you work in Self-Service industry, this post will certainly help you in understanding:

1. Fundamental concepts related to SST
2. What are the Modes in which SST operates
3. What is a Mode Handler
4. How Mode Handler eorks
5. How to implement a Mode Handler

To get the complete code, please send me an email and I will reply to you with a copy of the working project.

Cheers!
JS

Thursday, August 4, 2011

Iterating through rows in SQL Server

Iterate through each row in table using while loop in SQL

Hi,

You may face a situation in which you need to iterate through rows in a table one at a time and perform some operation on the data of the row. Note that, set based operations are highly efficient in SQL server and row based operation is not recommended. Suppose, you have a table and you need to run an SP on each row of the table. One possible solution is to use cursors, which are complex to write and also not very efficient. An alternative and easier method is to use the while loop.

You will need to copy rows from the original table into a temp table. Let’s create a temp table to use in this example:

create table #tempList(Seq int, Color varchar(10))

insert into #tempList values(1, 'Red')
insert into #tempList values(2, 'Green')
insert into #tempList values(3, 'Blue')
insert into #tempList values(4, 'Black')
insert into #tempList values(5, 'White')

Here, we are manually inserting rows, you can use select into to insert rows into temp table from the original table. Now, let’s use while loop to go through each row of this temp table and print it. You can store column values in some variables and do your operations like calling SPs.

declare @Seq int
declare @Color varchar(10)

while (select count(*) From #tempList) > 0
begin

-- get the row
select top 1 @Seq = Seq, @Color = Color from #tempList

-- perform some operation
select @seq, @Color

-- delete it from temp table
delete from #tempList where Seq = @Seq

end

We are selecting top 1 row and then performing some operation on it (printing in our case). Then, we delete this row from the temp table and repeat the aforementioned steps until there are no rows left in the temp table.

This method may not be the best one in terms of execution time and dependency on temp table, but works well for one-time tasks such as quick report generation directly through SQL Server Management Studio.

Cheers!
JS

Wednesday, August 3, 2011

How to Create Dynamic Forms in .NET (WPF, ASP .NET)

Creating forms through .Net code-behind

Why do we need Dynamic Forms

Generating data entry forms in WPF is not difficult. In fact, it is very easy and convenient to generate forms dynamically. Form generation at runtime has three major advantages over forms designed at design time:

1. You can add/remove controls without changing the code.
2. Control names and other properties can be changed without changing the code.
3. Layout of the form can be changed without changing the code.


Let’s take the example of a simple membership subscription form. The following are the initial UI requirements of this form as communicated by the customer:

1. The form will contain a label and a textbox for email address.
2. The form will contain a label and a textbox for password.
3. The form will contain a label and a textbox for first name.
4. The form will contain a label and a textbox for last name.
5. The form will contain a scrollable read-only multi-line textbox displaying the terms of use.
6. The form will contain a checkbox which says Agree to Terms
7. The form will contain a submit button.


This simple form can be designed within minutes by any .NET programmer. However, if tomorrow, the customer comes back and requests an additional text box to capture user’s phone number, the programmer needs to change the code to include these UI elements. If the customer comes back after every one month and requests the same type of change, then the work becomes redundant and a lot of useful time is wasted in adding text or check boxes or other UI elements.

The solution to this problem is to switch from creating static to dynamic forms.


What are Dynamic Forms

A dynamic form is one about which we are not sure how it will look like at runtime. A dynamic form is created in code-behind and in design-view may appear vacant because UI elements are not included in the form by the programmer at design-time.

It is painted dynamically at runtime. The controls to be painted on the form are usually stored in a database. The application simply fetches the list of UI elements to be painted from the database and for each element, creates an appropriate control on the form.

If any change is required in UI, all we need to do is add/remove/update records in the database. The client can be given a simple tool/script to do the changes in the database or the programmer could do so for them. If the programmer is charging for 5 hours to make this change but he is spending only 1 hour due to dynamic form, then it implies that the company is getting free money for additional 4 hours. This is a great strategy to increase revenues.


How to Implement Dynamic Forms

We will implement a sample dynamic form in WPF client application. The following are the assumptions:

Database

The database has the following tables:

a. Table to store form information
Form(FormId, Title, Description)

b. Table to store UI elements properties
Controls(ControlId, Name, DisplayName, Type, IsReadonly, DefaultValue)

c. Table to store values of controls like combo box/drop down list, etc.
ControlValues(ControlId, Value)

d. Table to associate many-to-many relationship of forms and controls
FormControls (FormId, ControlId, DisplayOrder )

Here is the sample data:

Form:
(1, 'Subscription', 'Membership Subscription Form')


Controls:
1, 'txtEmail', 'Email Address', 2, 'N', NULL
2, 'txtPassword', 'Password', 2, 'N', NULL
3, 'txtFName', 'First Name', 2, 'N', NULL
4, 'txtLName', 'Last Name', 2, 'N', NULL
5, 'txtTerms', 'Terms of Use', 2, 'Y', 'Some agreement text'
6, 'chkAgree', 'Agree to Terms', 6, 'N', NULL
7, 'btnSubmit', 'Submit', 10, 'N', NULL


FormControls (FormId, ControlId, DisplayOrder )
1,1,3
1,2,4
1,3,1
1,4,2
1,5,5
1,6,6
1,7,7
So, we defined a form in which the controls will appear in this order:

First Name, Last Name, Email Address, Password, Terms of Use, Agree to Terms, and Submit.

Application

The data access layer is available to read data from the tables. The layer can be written in ADO .NET or LINQ, or some other technology, all we need is a list a methods to perform operations on database tables.

We will use Stack Panels to display controls on the form. A stack panel is basically a container which can contain multiple controls to display either horizontally or vertically. We will display controls in rows, each row will be implemented through a stack panel, so that all the controls contained in one stack panel will appear in one row.

StackPanel1
StackPanel2
StackPanel3
StackPanel4
StackPanel5

StackPanel6
StackPanel7

The following code demonstrates how we are fetching the list of controls through database and how are we painting them dynamically on the form:


public void PaintForm(int FormID)

{

InitializeComponent();



// get form details

Form ThisForm = GetFormDetailsFromDB(FormId);

// fill up static content on the form first

lblHeading.Content = ThisForm.Title;

lblPurpose.Content = ThisForm.Purpose;

lblDescription.Content = ThisForm.Description;



// get the list of controls to paint on this form

var ControlsSet = (List)ThisContext.GetFormControls(FormId);



foreach (var control in ControlsSet)

{

StackPanel sp = new StackPanel();

sp.Orientation = Orientation.Horizontal;

sp.Margin = new Thickness(3);



switch (control.Type)

{ // text box

case 2:

{

TextBlock textBlock = new TextBlock();

textBlock.Text = control.DisplayName + ": ";

textBlock.Width = 80;



TextBox textBox = new TextBox();

textBox.Name = control.Name;

textBox.Width = 150;

this.RegisterControl(textBox.Name, textBox);



if (control.DefaultValue != String.Empty)

textBox.Text = control.DefaultValue;



if (control.IsReadOnly != null)

{

if (control.IsReadOnly.ToUpper() == "Y")

textBox.IsReadOnly = true;

}



sp.Children.Add(textBlock);

sp.Children.Add(textBox);



break;

}



case 3:

{ // combo box

TextBlock textBlock = new TextBlock();

textBlock.Text = control.DisplayName + ": ";

textBlock.Width = 80;



ComboBox comboBox = new ComboBox();

comboBox.Width = 80;

comboBox.Name = control.Name;

this.RegisterControl(comboBox.Name, comboBox);



var values = GetControlValues(control.Id);



foreach (var ThisValue in (IEnumerable)values)

{

comboBox.Items.Add(ThisValue.Value);

}



if (control.DefaultValue != String.Empty)

comboBox.SelectedValue = control.DefaultValue;



if (control.IsReadOnly != null)

{

if (control.IsReadOnly.ToUpper() == "Y")

comboBox.IsEnabled = false;

}



sp.Children.Add(textBlock);

sp.Children.Add(comboBox);



break;

}



case 5:

{ // date picker

TextBlock textBlock = new TextBlock();

textBlock.Text = control.DisplayName + ": ";

textBlock.Width = 80;



DatePicker datePicker = new DatePicker();

datePicker.Name = control.Name;

this.RegisterControl(datePicker.Name , datePicker);



if (control.DefaultValue != String.Empty)

datePicker.SelectedDate = Convert.ToDateTime(control.DefaultValue);



if (control.IsReadOnly != null)

{

if (control.IsReadOnly.ToUpper() == "Y")

datePicker.IsEnabled = false;

}



sp.Children.Add(textBlock);

sp.Children.Add(datePicker);



break;

}



case 6:

{ // check box



CheckBox checkBox = new CheckBox();

checkBox.Name = control.Name;

checkBox.Content = control.DisplayName;

this.RegisterControl(checkBox.Name , checkBox);



if (control.DefaultValue != null)

{

if (control.DefaultValue == "Y")

checkBox.IsChecked = true;

else

checkBox.IsChecked = false;

}



if (control.IsReadOnly != null)

{

if (control.IsReadOnly.ToUpper() == "Y")

checkBox.Enabled = false;

}



sp.Children.Add(checkBox);



break;

}





case 10:

{ // button

Button button = new Button();

button.Name = control.Name;

button.Content = control.DisplayName;

button.Width = 50;



sp.Children.Add(button);



break;

}



default:

{

break;

}

}



FormBase.Children.Add(sp);

}

}



private void RegisterControl(string ControlName, Control ThisControl)

{ // register control because we will need to read the value entered by user on form submission

if (this.FindName(ControlName) != null)

this.UnregisterName(ControlName);

this.RegisterName(ControlName, ThisControl);

}


You must be wondering that how are we determining the order of controls to display in rows(stack panels). Well, the method GetFormDetailsFromDB should do a select query on FormControls table and order by DisplayOrder. In this way, we will simply start painting controls in the same order as that of the record-set we received.

Reading Forms Data Entered by User
 The logic is pretty simple here. Go through all stack panels in the form and search each control by its name. The following code will read the values entered by user in the form. We are storing the values in a hashtable ControlValues for future use.


public void ReadFilledForm(int FormId)
{
Hashtable ControlsValues = new Hashtable();
var ControlsMap = GetFormControls(FormId)

// now save form values
foreach(var control in ControlsMap)
{
foreach (StackPanel sp in FormBase.Children)
{
Control ThisControl = (Control) FindName(control.Name);
if (ThisControl != null)
{
if (ThisControl.GetType().ToString().Equals("System.Windows.Controls.TextBox"))
{
TextBox NewTextBox = (TextBox)ThisControl;
ControlsValues.Add(control.Id, NewTextBox.Text);
}
if (ThisControl.GetType().ToString().Equals("System.Windows.Controls.ComboBox"))
{
ComboBox NewComboBox = (ComboBox)ThisControl;
ControlsValues.Add(control.Id, NewComboBox.SelectedValue);
}
else if (ThisControl.GetType().ToString().Equals("System.Windows.Controls.CheckBox"))
{
CheckBox NewCheckBox = (CheckBox)ThisControl;
if (NewCheckBox.IsChecked == true)
ControlsValues.Add(control.Id, "Y");
else
ControlsValues.Add(control.Id, "N");
}
if (ThisControl.GetType().ToString().Equals("System.Windows.Controls.DatePicker"))
{
DatePicker NewDatePicker = (DatePicker)ThisControl;
ControlsValues.Add(control.Id, NewDatePicker.SelectedDate);
}

break;
}
}
}
}


I hope the above code snippets will help readers in getting acquainted with dynamic forms creation in WPF. The same code can be reused with little changes in ASP .NET web forms.

Cheers!
JS

Tuesday, June 28, 2011

Truck Routing Algorithm

Hi,

Few weeks back, I got a chance to work with a friend of mine on a Supply Chain problem. We wanted to develop and code an algorithm to produce an optimal solution. Before discussing the details of the solution, lets explore the problem first.


Problem

We have a graph of nodes. One of these nodes is the origin. We will call it 'source'. The source maintains a repository of goods to be delivered to other nodes in the graph. To deliver goods, we have a delivery truck which can carry a certain quantity of goods. We call it the truck capacity Ct. The delivery truck needs to visit each node and deliver the required quantity of goods. The required quanity of goods may or may not be different for each node. If the total requirement in the entire graph is, lets say 1000 units and the capacity of the truck is 100 units, the truck will deliver goods to nodes until its capacity is exhausted. It will then come back to the source for loading and will then resume visiting the left-out nodes. The whole process will continue until the truck serves all nodes in the graph.

We want to identify the optimal solution for this problem so that:

1. All nodes are served, keeping the requirement constraint of each node and the capacity of the truck

2. Best routes are identified with minimal distances to save travel time and expense


Solution

We initially targetted to solve the problem by using Tabu algorithm. However, we then decided to use 'clustering'. Clustering majorly implies grouping together similar items into groups or clusters. The similarity criterion may depend on the type of data. In most cases, the similarity criterion is least distant. In our problem, we cannot rely on least distance only. We not only need to make sure that routes/regions with least distance (between contained nodes) are identified but also the capacity constraint is not compromised. Therefore, we will cluster nodes on two criteria:

1. Clusters/Regions/Routes formed by nodes have the least distance/length

2. The total requirement of a cluster does not exceed the loading capacity of the truck

So, our solution works like this:

1. Load truck with goods.

2. Pick out a region and serve all nodes within that region.

3. Come back to source for reloading.

4. Repeat steps 1 to 3 until all regions are served

5. Come back to source

We devise the following algorithm to solve the problem.


Algorithm


1. Read network information from file
2. Calculate number of regions which can serve the whole network

3. Randomly assign nodes to regions such that the capacity of region is less than the capacity of truck

4. For each region, shuffle nodes within a region and get the best possible route with minimum length

5. Treat it as a possible solution

6. Run steps 2 to 4 for the given number of iterations

7. If the total length of all regions in this iteration is less than previous optimal solution, make it optimal solution

8. End with the optimal solution achieved


Source Code

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

namespace RoutingAlgo
{
    public partial class Form1 : Form
    {
        private int[,] Nodes = new int[5000, 4];
        private int NodesCount = 0;
        int TotalCapacity = 0;

        private ArrayList Regions = new ArrayList();
        int RegionsCount = 0;

        private double BestDistance = double.MaxValue;
        private string BestRoute = String.Empty;

        public Form1()
        {
            InitializeComponent();
            GetCaseData();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        
        }

        private int GetCaseData()
        {   // Read network info from file
            FileStream fs = null;
            StreamReader Reader = null;
            int status = 0;

            try
            {
                fs = new FileStream(@"c:\CaseData.txt", FileMode.Open, FileAccess.Read);
                Reader = new StreamReader(fs);

                string SingleNode = String.Empty;

                while ((SingleNode = Reader.ReadLine()) != null)
                {   // read file line by line
                    //split each line with comma as delimiter and populate arrays
                    string[] NodeDetails = SingleNode.Split(',');
                    Nodes[NodesCount, 0] = int.Parse(NodeDetails[0]);
                    Nodes[NodesCount, 1] = int.Parse(NodeDetails[1]);
                    Nodes[NodesCount, 2] = int.Parse(NodeDetails[2]);
                    Nodes[NodesCount, 3] = int.Parse(NodeDetails[3]);

                    // Find total capacity required in the network
                    TotalCapacity = TotalCapacity + Nodes[NodesCount, 3];
                    lstNodes.Items.Add(SingleNode);
                
                    NodesCount++;
                }
            }
            catch(Exception exc)
            {
                status = 1;
            }
            finally
            {
                if (Reader != null)
                    Reader.Close();
                if (fs != null)
                    fs.Close();
            }
            return status;
        }

        private int GetRegionsCount()
        {   // calculate number of regions required to serve the network
            try
            {   // divide total network capacity divided by truck capacity, round up answer
                int Capacity = int.Parse(txtCapacity.Text);
                if (TotalCapacity % Capacity == 0)
                    return TotalCapacity / Capacity;
                else
                    return (TotalCapacity / Capacity) + 1;
            }
            catch (Exception exc)
            {
                return 0;
            }

        }

        private int InitializeRegions()
        {   // initialize regions array
            RegionsCount = GetRegionsCount();
            for (int i = 0; i < RegionsCount; i++)
            {   // initialize array for each region
                ArrayList ThisRegion = new ArrayList();
                ThisRegion.Add(0);  // first element will store the capacity of the region
                ThisRegion.Add(Nodes[0, 0]); // origion will be the second node in every region
                Regions.Add(ThisRegion);
            }

            return 0;
        }

        private int AssignNodesToRegions()
        {   // randomly assign nodes to regions
            Random Generator = new Random();

            for (int i = 1; i < NodesCount; i++)
            { // for each node, assign randomly using random number generator
                while (true)
                {
                    ArrayList ThisRegion = (ArrayList)Regions[Generator.Next(RegionsCount)];
                    if (((int)ThisRegion[0] + Nodes[i, 3]) <= int.Parse(txtCapacity.Text))
                    {
                        ThisRegion[0] = (int)ThisRegion[0] + Nodes[i, 3];
                        ThisRegion.Add(Nodes[i, 0]);
                        break;
                    }
                }

            }

            return 0;
        }

        private int DisplayResults()
        {   // displays result in Results text box
            txtRegions.Text = txtRegions.Text + "------------------" + "\n";

            for (int i=0; i<RegionsCount; i++)
            {
                ArrayList ThisRegion = (ArrayList)Regions[i];
                for (int j=0; j<ThisRegion.Count; j++)
                {
                    txtRegions.Text = txtRegions.Text + ThisRegion[j] + "|";
                }

                txtRegions.Text = txtRegions.Text + " [" + GetRegionLength(ThisRegion) + "]\n";
            }

            return 0;
        }

        private ArrayList GetAlternativeRoute(ArrayList OriginalRegion, int Idx1, int Idx2)
        {   // give a route, generate a new route by swapping two nodes within a region
            ArrayList TempNode = new ArrayList(OriginalRegion);

            // swapping two nodes within a region
            int temp = (int)OriginalRegion[Idx1];
            OriginalRegion[Idx1] = OriginalRegion[Idx2];
            OriginalRegion[Idx2] = temp;

            return TempNode;
        }

        private int ShuffleNodesInRegion()
        {   // try all combinations of nodes within a region to acquire least distance
            for (int k=0; k<RegionsCount; k++)
            {
                ArrayList ThisRegion = (ArrayList)Regions[k];
                for (int i=2; i<ThisRegion.Count-1; i++)
                {
                    for (int j=i+1; j<ThisRegion.Count; j++)
                    {   // swap every two nodes
                        ArrayList AlternateRoute = GetAlternativeRoute(ThisRegion, i, j);
                    
                        if (GetRegionLength(AlternateRoute) < GetRegionLength(ThisRegion))
                        {   // if new route is better, make it permanent
                            ThisRegion.Clear();
                            Regions.RemoveAt(k);
                            Regions.Insert(k, AlternateRoute);
                            ThisRegion = (ArrayList)Regions[k];
                        }
                    }
                }
            }

            return 0;
        }


        private int CheckBestRoute()
        {   // for each set of regions calculated, see if this iteration produced an optimal solution
            double Distance = 0;

            for (int k = 0; k < RegionsCount; k++)
            {
                ArrayList ThisRegion = (ArrayList)Regions[k];
                Distance = Distance + GetRegionLength(ThisRegion);
            }

            if (Distance < BestDistance)
            {   // this solution is better than previous optimal solution
                BestDistance = Distance;
                BestRoute = String.Empty;

                for (int i = 0; i < RegionsCount; i++)
                {
                    ArrayList ThisRegion = (ArrayList)Regions[i];
                    BestRoute = BestRoute + "[" + ThisRegion[0] + "]";
                    for (int j = 1; j < ThisRegion.Count; j++)
                    {
                        BestRoute = BestRoute + ThisRegion[j] + "|";
                    }
                    BestRoute = BestRoute + "\n";
                }
            }
        
            return 0;
        }

        private void btnRun_Click(object sender, EventArgs e)
        {   // run routing algorithm
            try
            {
                for (int i = 0; i < int.Parse(txtIterations.Text); i++)
                {
                    InitializeRegions();
                    AssignNodesToRegions();
                    ShuffleNodesInRegion();
                    DisplayResults();
                    CheckBestRoute();
                    Regions.Clear();
                }

                txtRegions.Text = txtRegions.Text + "\nBest Route\n----------\n" + BestRoute;
                txtRegions.Text = txtRegions.Text + "\nBest Distance\n----------\n" + BestDistance.ToString();
            }
            catch (Exception exc)
            {
                txtRegions.Text = exc.ToString();
            }
        }

        private double GetRegionLength(ArrayList ThisRegion)
        {   // calculate length of a region
            double RegionDistance = 0;
            for (int i=1; i<ThisRegion.Count-1; i++)
            {   // add distances of subsequent nodes
                Point P1 = new Point(Nodes[(int)ThisRegion[i], 1], Nodes[(int)ThisRegion[i], 2]);
                Point P2 = new Point(Nodes[(int)ThisRegion[i+1], 1], Nodes[(int)ThisRegion[i+1], 2]);
                RegionDistance = RegionDistance + CalculateEuclideanDistance(P1, P2);
            }
        
            // add distance of first node to last node as truck will need to go back to the origin
            Point P0 = new Point(Nodes[(int)ThisRegion[0], 1], Nodes[(int)ThisRegion[0], 2]);
            Point Pn = new Point(Nodes[(int)ThisRegion[ThisRegion.Count - 1], 1], Nodes[(int)ThisRegion[ThisRegion.Count - 1], 2]);
            RegionDistance = RegionDistance + CalculateEuclideanDistance(P0, Pn);

            return RegionDistance;
        }

        private double CalculateEuclideanDistance(Point A, Point B)
        {   // return euclidean distance between two points in graph
            return Math.Sqrt(Math.Pow(A.X - B.X, 2) + Math.Pow(A.Y - B.Y, 2));
        }
    }
}


Graph Representation

We will take graph information as an input file. The following is a sample file:
0,82,76,0
1,96,44,19
2,50,5,21
3,49,8,6
4,13,7,19
5,29,89,7
6,58,30,12
7,84,39,16
8,14,24,6
9,2,39,16
10,3,82,8
11,5,10,14
12,98,52,21
13,84,25,16
14,61,59,3
15,1,65,22
16,88,51,18
17,91,2,19
18,19,32,1
19,93,3,24
20,50,93,8
21,98,14,12
22,5,42,4
23,42,9,8
24,61,62,24
25,9,97,24
26,80,55,2
27,57,69,20
28,23,15,15
29,20,70,2
30,85,60,14
31,98,5,9 
 
Each line represents a node. The first node is the source. The first component in a node represents node identifier, the second and third are X and Y co-ordinates respectively, and the last component is goods requirement for the node.


Results
The following is the screenshot of the user interface:




The higher the number of iterations, the better the solution. For 20 iterations, we got the solution in 2 secs. For 100 iterations, we got the solution in 10 secs with a significant improvement in distance.


For 200 iterations, the program took 31 secs and produced a better result. However, we notice that as we increase the number of iterations further, the execution time is increasing rapidly while we do not see drastic improvement in solution.



Therefore, we can conclude that 200 is a good number of iterations to get optimal solution.


Conclusion

The program succeeds to provide good results in reasonable time. However, an improvement in data structrues can reduce the execution time of the program. Moreover, the algorithm still has room for improvement. We may do these modifications in future, but for now we are pretty happy with the results.

Cheers!
JS

Saturday, April 23, 2011

DHCP client fails to start- Error 5- Access is denied.

DHCP client not starting Windows 7- Error 5- Access is denied.

Hi,


Today, I faced a pretty strange problem with my HP notebook running Windows 7. I was not able to connect to the wireless network at my friend's home. Initially, I had thought it could be a minor problem which would be resolved once I disable/enable my network adapter and restart my notebook. However, this did not resolve the issue. In the end, I checked if router was configured to use DHCP and restarted the router as well. My problem was still unsolved.

I came back home and opened my laptop. Bummer, my wireless connection was again not working! At this point, I decided to take the troubleshooting to the next step and opened System Event Logs. To my surprise, there were several errors reported by services which failed to start. Some of those services were pertinent to network such as DHCP client and Diagnostic Policy service. I tried to manually start DHCP client service in Service Manager but got the error- Error 5: Access is denied.


After spending some time on Google, I was finally able to resolve the issue. Open regedit and go to HKLM/System/CurrentControlSet/services. Right click on services and select Permissions. Assign full control to LOCAL SERVICE and SERVICE users on all subkeys of services key. I restarted my notebook, and yes, all services launched successfully this time and I was connected to the Internet.


Cheers!


JS