N-Tier Development with Microsoft .NET : Part III

The last installment in this series detailed more on the middle tier business faade and how to create a Web Service Export Proxy to have a physically separated middle tier. This is the final installment in the series and it will deal with hooking the proxy into the Employees.aspx page and will show another feature that is now available to the presentation tier for the web that was not in Asp that greatly reduces maintenance.

The zip file contains a web project named DDLTest. The Employees.aspx page, the EmployeesAcc.aspx page and the Admin.aspx page are in this project. The EmployeesAcc.aspx page accesses the Access DataLayer database, the Admin.aspx page is to update the ParameterCache when new procedures are added to an application or procedures are altered. This article will focus mainly on Employees.aspx as illustrated in Figure 1.

Figure 1.

NTierD2P3Img1.jpg

This page has insert, update, delete and find methods that point to the HumanResource Web Service, the TVanover.DDL, and the DataLayer Sql Server database. A first name and a last name can be entered to search for a given name similar to the one entered and the records are returned and bound to a datagrid. The button labeled Find calls the SearchEmployees method shown in Listing 1. This method call instantiates the exported class from the Personnel.cs file that was generated in the previous article.

Listing 1

private void SearchEmployees()
{
Personnel oPersonnel =
new Personnel();
DataSet ds =
new DataSet();
try
{
ds = oPersonnel.SearchEmployees(
txtFirstName.Text,txtLastName.Text);
drgEmployees.DataSource = ds;
drgEmployees.DataBind();
}
catch(Exception oException)
{
if (!EventLog.SourceExists(APPLICATION_NAME))
{
EventLog.CreateEventSource(APPLICATION_NAME,
EVENT_LOG);
}
EventLog.WriteEntry(oException.Source, oException.Message,
EventLogEntryType.Error );
}
finally
{
ds.Dispose();
}
}

There is nothing all that out of the ordinary about this method call other than the fact that the proxy class allows the presentation tier to execute a the actual code on another machine. This allows the physical tier separation giving the ability to scale an application out limited only by the number of machines added to run the application.

The last article also spoke of making asynchronous calls to the HumanResource Web Service. This is done on the Insert, Update, and Delete methods on the Employees.aspx page allowing the processing to continue while the record is being altered in the database. Examine the code on the Insert button in Listing 2. The btnAddNew_Click event does some very basic checking of fields for empty values inside the try catch finally block. Notice that even though this is a transactional method that this tier has no knowledge of that fact as it is abstracted from that logic.

Listing 2

private void btnAddNew_Click(object sender, System.EventArgs e)
{
try
{
if(txtFirstName.Text.Trim() != string.Empty &&
txtLastName.Text.Trim() !=
string.Empty &&
txtSSN.Text.Trim() !=
string.Empty )
{
Personnel oPersonnel =
new Personnel();
// Begin the Async call to AddEmployee
IAsyncResult oResult = oPersonnel.BeginAddEmployee(txtFirstName.Text, txtMiddleInitial.Text, txtLastName.Text, txtSSN.Text, null, null);
//wait for the callback
oResult.AsyncWaitHandle.WaitOne();
}
}
catch(Exception oException)
{
if (!EventLog.SourceExists(APPLICATION_NAME))
{
EventLog.CreateEventSource(APPLICATION_NAME,
EVENT_LOG);
}
EventLog.WriteEntry(oException.Source, oException.Message,
EventLogEntryType.Error );
}
finally
{
//reload the searched page
SearchEmployees();
}
}

Once again the Personnel class is instantiated from the Personnel.cs file that was generated with the wsdl.exe tool. The IAsyncResult has methods that control the current thread execution and can block the current thread completion until a callback message has been received in several various states. Notice that for this instance the AsyncWaitHandle.WaitOne() is used. The following table lists the various states of this AsyncWaitHandle.

WaitAll() Waits for all elements to receive a callback signal.
WaitAny() Waits for any one of the elements to receive a callback signal.
WaitOne() Waits for the WaitHandle to receive a callback signal

In the example shown the service will execute and there will barely be any noticeable program execution halt as the current thread is allowed to continue almost simultaneously.

Listing 3 demonstrates an alternate possible use for this type of processing.

Listing 3

private void btnAddNew_Click(object sender, System.EventArgs e)
{
try
{
if(txtFirstName.Text.Trim() != string.Empty &&
txtLastName.Text.Trim() !=
string.Empty && txtSSN.Text.Trim() != string.Empty )
{
Personnel oPersonnel =
new Personnel();
// Begin the Async call to AddEmployee
IAsyncResult oResult = oPersonnel.BeginAddEmployee(txtFirstName.Text,
txtMiddleInitial.Text, txtLastName.Text, txtSSN.Text,
null, null);
//wait for the callback
oResult.AsyncWaitHandle.WaitOne();
//Do some more processing here
//return new employeeID
m_iEmployeeID = oPersonnel.EndAddEmployee(oResult);
}
}
catch(Exception oException)
{
if (!EventLog.SourceExists(APPLICATION_NAME))
{
EventLog.CreateEventSource(APPLICATION_NAME,
EVENT_LOG);
}
EventLog.WriteEntry(oException.Source, oException.Message, EventLogEntryType.Error );
}
finally
{
//reload the searched page
SearchEmployees();
}
}

In this instance the oPersonnel would return the new EmployeeID that was generated on the insert method after additional processing had taken place.

A Callback method could also have been generated and sent to the oResult object that would take to additional parameters where the nulls where passed. The first parameter would be an AsyncCallback object that takes ClassName.MethodName as a parameter, and the second parameter is the oPersonnel object.

After the AsyncWaitHandle receives the callback signal and allows the thread to continue based on which method was selected the finally block executes and reloads and binds the new data in the datagrid.

Additional UI Possiblities
Now that developers have .Net there are some things that are possible on the UI side that make development time much reduced through OOP that was not previously available to Web Developers beyond what has been shown through the asynchronous processing. Notice the class declaration on the Employees.aspx page shown in listing 4. The Employees class inherits System.Web.UI.Page. This means that all of the functionality that is contained in that Page object are now static members of the Employees class. These include the Response, Request, and all of the other objects and methods needed to build web based presentation media.

Listing 4

public class Employees : System.Web.UI.Page

This can be further extended to help developers reuse and standardize functionality that in part was limited to using include files. Inheriting functionality also allows better maintenance as when a bug is found it can be corrected in several places by correcting the base method. While this does not replace the need for include files it should be noted that Inheritance is much more powerful.

Notice Listing 5 for the Inherited class declaration. The Inherited.aspx page is not using the default base class from the CLR in the same manor as the Employees.aspx page nonetheless System.Web.UI.Page is still the base class in a since.

Listing 5

public class Inherited : TVanover.Web.HRPage

The TVanover.Web class library needs to be expanded to demonstrate this. There are two classes in this library. The Page.cs and the HRPage.cs files contain these. Notice the class declaration on the Page class is exactly the same as the Employees class in that each inherits System.Web.UI.Page. This new Page class also has several other methods defined that might be common across a web application. RequestString, RequestBool, RequestShortDate, RequestInteger, CheckSecurity and the SecurityAccess enumeration. Notice the HRPage class declaration in listing 6.

Listing 6

public class HRPage: Page

The HRPage inherits the Page, which has a base class of the CLR Page object. It only has one method defined for filtering employees. Notice the code in the Inherited.aspx code behind in Listing 7.

Listing 7

Private void btnFind_Click(object sender, System.EventArgs e)
{
Personnel oPersonnel =
new Personnel();
DataSet dsPersonnel =
new DataSet();
dsPersonnel = oPersonnel.SearchEmployees("","");
//statically inherited methods
string columnName = RequestString("HID_ColumnName");
int EmployeeID = RequestInteger("HID_EmployeeID");
string Filter = FilterEmployees(txtFirstName.Text, columnName);
int securityAccess = CheckSecurity("Timmy","CanIGetHere");
string UserStatus = "Prospective looser";
switch(securityAccess)
{
case (int)SecurityAccess.NoAccess :
UserStatus = "looser";
break;
case (int)SecurityAccess.ReadAccess :
UserStatus = "almost looser";
break;
case (int)SecurityAccess.WriteAccess :
UserStatus = "Not so much a looser";
break;
case (int)SecurityAccess.WriteUpdateAccess :
UserStatus = "What's a looser";
break;
case (int)SecurityAccess.WriteUpdateDeleteAccess :
UserStatus = "DaMan!";
break;
}
dsPersonnel.Tables[0].DefaultView.RowFilter = Filter;
drgEmployees.DataSource = dsPersonnel.Tables[0].DefaultView;
drgEmployees.DataBind();
}

The first thing to notice is that the RequestString and the RequestInteger static methods are returning values to this page. Also notice that the FilterEmployees method as well as theCheckSecurity methods are also called. The SecurityAccess enumeration defined on the Page object is also available to the .aspx page that has inherited the base class on which it is defined. Other uses for this might include error page redirection, exception handling, or other pieces needed for an application as a whole.

This concludes this series on this particular proof of concept. In conclusion the future holds many new techniques and possibilities that are now possible with .Net. and many different patterns will arise over the next few years as developers start turning toward this new tool that Microsoft has bestowed upon the world.

As an author I must give recognition to those who have helped, pushed, driven, and shared both time and knowlege . Acknowlegments go out to the following for these reasons:

Jason Wisener
Mike Houston
Dan Fox


Similar Articles