r tanenbaum .net portfolio

17
Rob rtan bert Tanenbaum [email protected] 732.819.7533

Upload: robert-tanenbaum

Post on 27-May-2015

469 views

Category:

Documents


1 download

DESCRIPTION

Portfolio of .Net work by Robert Tanenbaum showing both code and screenshots of Windows Forms, Web Sites, polymorphism, T-SQL and other .Net technologies.

TRANSCRIPT

Page 1: R Tanenbaum .Net Portfolio

Robert Tanenbaum

[email protected]

Robert Tanenbaum

[email protected]

732.819.7533

Page 2: R Tanenbaum .Net Portfolio

CONTENTS:

Demonstrate the use of polymorphism

Demonstrate the use of polymorphism

Use of a strongly typed dataset

Use of a strongly typed dataset

Showing data entry field validation

Showing data entry field validation

Use of ADO.Net and T-SQL stored procedures

Use of ADO.Net and T-SQL stored procedures

Demonstrate role-based security and navigation

Demonstrate role-based security and navigation

Proper use of n-tier layer architecture

Proper use of n-tier layer architecture

Using an AJAX client-side control

Using an AJAX client-side control

Use of CSS classes to unify a color scheme

Use of CSS classes to unify a color s

Demonstrate the use of polymorphism – screenshot.

Demonstrate the use of polymorphism – code sample.

Use of a strongly typed dataset – screenshot.

Use of a strongly typed dataset – code sample.

Showing data entry field validation – screenshot.

Showing data entry field validation – code sample.

SQL stored procedures – screenshot.

SQL stored procedures – code sample.

based security and navigation – screenshot.

based security and navigation – code sample.

tier layer architecture – screenshot.

tier layer architecture – code sample.

side control – screenshot.

side control – code sample.

Use of CSS classes to unify a color scheme – screenshot.

Use of CSS classes to unify a color scheme – code sample.

Page 3

Page 4

Page 5

Page 6

Page 7

Page 8

Page 9

Page 10

Page 12

Page 13

Page 14

Page 15

Page 16

Page 16

Page 17

Page 17

Page 3: R Tanenbaum .Net Portfolio

Demonstrate the use of polymorphism – screenshot. Page 3

This screenshot shows the Member Lookup tab for the RT Library Phase 2 project as developed using windows

forms. What is interesting about this particular screen is that, although it was not specified in the project

requirements, there are two ways that the member data can be displayed. First, the user can enter the member

identifier in the text box and click the Lookup button. Alternatively, the user can enter the member identifier

and simply hit the tab key.

Normally, clicking on a button and tabbing out of a text box trigger two different kinds of events which would

require nearly identical code --- code to display the member data --- to be written twice. Having nearly identical

code in more than one place is a problem for code maintenance. However, by employing the C# use of

polymorphism, Robert was able to avoid this problem.

The following code sample shows how this is done.

Page 4: R Tanenbaum .Net Portfolio

Demonstrate the use of polymorphism – code sample. Page 4 Two different actions performed by the user have the same desired result – perform a lookup and display of the

member data.

Here is the code for the event handler when clicking the Lookup button.

Here is the code for the event handler when tabbing out of the member identifier text box:

The Click event passes an EventArgs object to its event handler, but the Validating event passes a

CancelEventArgs object to its handler. The CancelEventArgs object has the Cancel property which is used when

validating a field, and the EventArgs object lacks that property. You would think that calling the

lookupButton_Click method with a CancelEventArgs object would fail. However, it does not fail, because a

CancelEventArgs object inherits from EventArgs and can be implicitly cast to an EventArgs object.

But wait. How can we then access the Cancel property on the EventArgs object in the lookupButton_Click

method? That problem is solved by the code highlighted in yellow which tests to be sure that the underlying

object is a CancelEventArgs object and then casts the EventArgs object to its underlying identity and legitimately

accesses the Cancel property.

private void memberIdTextBox_Validating(object sender, CancelEventArgs e)

{

lookupButton_Click(sender, e);

}

private void lookupButton_Click(object sender, EventArgs e)

{

String errString = "";

String memberString = "";

Member myMember = null;

// Check that a valid MemberId is entered

myMember = isExistingMemberId(memberIdTextBox.Text, ref errString);

if (myMember == null)

{

if (e is CancelEventArgs)

{

// We were called from memberIdTextBox_Validating()

((CancelEventArgs)e).Cancel = true; // validation failed

}

errorProvider1.SetError((Control)memberIdTextBox, errString);

MemberStatusButton.BackColor = DisplayBackColor.errorColor;

MemberStatusButton.Text = errString;

return;

}

// The member lookup succeeded so let's build the display string

memberString = CreateMemberDataString(out backColor, myMember);

// Now display the string

MemberDisplay.BackColor = backColor;

MemberDisplay.Text = memberString;

}

Page 5: R Tanenbaum .Net Portfolio

Use of a strongly typed dataset – screenshot. Page 5

The data displayed in the DataGridView comes from a dataset defined by a strongly typed dataset which was

automatically generated by Visual Studio 2008 from the GetItems T-SQL stored procedure.

The following code sample shows how simple it is to acquire this dataset from the database using the C# highly

typed dataset generated by Visual Studio 2008.

Page 6: R Tanenbaum .Net Portfolio

Use of a strongly typed dataset – code sample. Page 6 This code sample shows how simple it is to acquire a dataset using the strongly typed dataset which was

automatically generated by Visual Studio 2008.

In just 3 simple statements highlighted in yellow above, the dataset is created and filled.

public ItemsDataSet GetItems(short memberNumber)

{

try

{

using (ItemsDataSet itemsDs = new ItemsDataSet())

{

using (ItemsTableAdapter itemsTab = new ItemsTableAdapter())

{

int ret_val = itemsTab.Fill(itemsDs.Items, memberNumber);

if (ret_val < 0)

{

throw new LibraryException(ErrorCode.GenericException,

"GetItems reports error retrieving Items from database");

}

return itemsDs;

}

}

}

catch (SqlException sqlEx)

{

if (sqlEx.State == 1)

{

throw new ArgumentOutOfRangeException("Missing member number", sqlEx);

}

throw new LibraryException(ErrorCode.GenericException, "SQL Error", sqlEx);

}

catch (Exception ex)

{

throw new LibraryException(ErrorCode.GenericException, ex.Message, ex)

}

}

Page 7: R Tanenbaum .Net Portfolio

Showing data entry field validation – screenshot. Page 7

There a few things to notice about this screen.

First, the fields are validated one-by-one as the user tabs through each field.

Second, when the Add adult button is clicked, all the data entry fields are validated before the action takes

place.

Third, an error provider component is included on this form and puts a little red circle next to each field which

failed validation.

Fourth, if the mouse cursor hovers over one of the red circles, the descriptive error message pops up to tell the

user why that field failed validation.

Fifth, notice that the Zip code and Phone number fields show parentheses and hyphens as guides to assist the

user to type in the proper format.

The following code sample describes something interesting about validating the phone number when taking the

guiding parentheses and hyphen into consideration.

Page 8: R Tanenbaum .Net Portfolio

Showing data entry field validation – code sample. Page 8

The business rules for the Library project permit a new adult member to be added without a phone number.

However, the validation of the phone number requires a little trick to check to see if no phone number was

entered at all. It is not possible to use length of the field to determine whether the field is empty because the

guiding parentheses and hyphen are counted in the length of the field. Also, we don’t want to store the

parentheses in the database table if no phone number is entered.

This code sample shows how to manage the data mask to sometimes consider the masking characters and to

sometimes ignore them.

The code above which is highlighted in yellow first turns the masking characters off so the length of use- entered

text can be checked. If there was any user-entered text, then the mask is turned back on before checking to see

if the phone number is in the correct format.

Similar code which selectively includes or excludes the masking characters when placing the phone number and

zip code into the object which is stored in the database.

private void phoneNumberTextBox_Validating(object sender, CancelEventArgs e)

{

MaskedTextBox ctrl = sender as MaskedTextBox;

if (ctrl != null)

{

// First check the length without the mask literals

// to see if anything was entered

ctrl.TextMaskFormat = MaskFormat.ExcludePromptAndLiterals;

if (ctrl.Text.Length > 0)

{

// Something was entered so include the mask literals and validate

ctrl.TextMaskFormat = MaskFormat.IncludeLiterals;

if (!isPhoneNumber(ctrl.Text))

{

// Failed the phone number test

e.Cancel = true;

errorProvider1.SetError(ctrl, "Not a phone number");

}

}

}

}

Page 9: R Tanenbaum .Net Portfolio

Use of ADO.Net and T-SQL stored procedures – screenshot. Page 9

This screenshot shows the result of a successful addition of a juvenile library member.

A number of things need to be done In order to add a new juvenile member to the library.

The name and birth date fields need to be validated according to the library’s business rules.

An adult sponsor id needs to be entered and validated to be sure the id belongs to an adult whose membership

is current.

The information about the adult sponsor needs to be retrieved and displayed.

Then the information about the juvenile member needs to be stored in the database and the successful result

needs to be displayed to the librarian.

The following code sample is an example of the ADO.Net code for taking the information about the juvenile

member and storing it in the database.

Page 10: R Tanenbaum .Net Portfolio

Use of ADO.Net and T-SQL stored procedures – code sample. Page 10

Here is the code which adds the juvenile member to the database.

Validate the arguments, setup the connection string and setup the input parameters.

Then setup the output parameters.

SqlParameter street = new SqlParameter("@street", SqlDbType.VarChar);

street.Direction = ParameterDirection.Output;

street.Size = 15;

procCmd.Parameters.Add(street);

SqlParameter city = new SqlParameter("@city", SqlDbType.VarChar);

city.Direction = ParameterDirection.Output;

city.Size = 15;

… etc. …

// set the parameter for the return value

SqlParameter rVal = new SqlParameter("@return_value", SqlDbType.Int);

rVal.Direction = ParameterDirection.ReturnValue;

procCmd.Parameters.Add(rVal);

public void AddMember(JuvenileMember member)

{

int ret_val = 0;

// Check for bad data being passed in

if (member == null)

{

throw new ArgumentOutOfRangeException("member",

"member object must not be null.");

}

// Set up the connection string

try

{

using (SqlConnection conn = new SqlConnection(LibraryConnectString))

{

conn.Open();

using (SqlCommand procCmd =

new SqlCommand("AddJuvenileMember", conn))

{

procCmd.CommandType = CommandType.StoredProcedure;

// Set the input parameter

procCmd.Parameters.AddWithValue("@lastname",

member.LastName);

procCmd.Parameters.AddWithValue("@firstname",

member.FirstName);

procCmd.Parameters.AddWithValue("@middleinitial",

member.MiddleInitial);

procCmd.Parameters.AddWithValue("@birth_date",

member.BirthDate);

procCmd.Parameters.AddWithValue("@adult_member_no",

member.AdultMemberID);

Page 11: R Tanenbaum .Net Portfolio

Now run the query, check the return code and save the returned values.

// Now run the NonQuery

procCmd.ExecuteNonQuery();

ret_val = (int)rVal.Value;

// Be sure we got the successful return value

if (ret_val != 0)

{

throw new LibraryException(ErrorCode.GenericException,

"Unknown error in AddJuvenileMember stored procedure");

}

// Now save all the returned values

// These first values should be non-Null

member.MemberID = (short)MemberNo.Value;

member.Street = (string)street.Value;

member.City = (string)city.Value;

member.State = (string)state.Value;

member.ZipCode = (string)zip.Value;

member.ExpirationDate = (DateTime)ExprDate.Value;

// These values might be null

member.PhoneNumber = phone_no.Value.GetType() == typeof(DBNull) ? "" :

(string)phone_no.Value;

// That's all there is to it.

}

}

}

// Handle the possible exceptions that were raised.

Page 12: R Tanenbaum .Net Portfolio

Demonstrate role-based security and navigation – screenshot. Page 12

This screenshot shows the Check In Item screen for the RT Library Phase 3 project as developed using ASP.Net

tools. The navigation and security controls, as well as the picture and heading are placed in a master page which

is the master for all pages in this website.

Access Security:

This application implements role-based security using ASP.Net login controls and is tied to an SQL Server

database. This screen is only accessible to users who are associated with the Librarian role.

Navigation:

There are 3 navigation elements on this page:

1. The TreeView control on the left shows all the pages accessible to a user in the role of Librarian.

2. A Menu control is on the top left and is shown expanded out horizontally.

3. Just above the main content is the SiteMapPath where this screen is located in the menu hierarchy.

Page 13: R Tanenbaum .Net Portfolio

Demonstrate role-based security and navigation – code sample. Page 13 The RT Library Phase 3 project implements role-based access security and navigation. The controls which

implement these functions are placed on a master page which is used as the template for all other pages on the

website.

Access security is enforced by strategically placing the web pages in a subfolder of the website. All of the

functions which are accessible to users who have the role of Librarian are in the Librarian subfolder. The web

server enforces access to the pages in the subfolder by following the instructions in the web.config file which is

also located in that subfolder. This is the web.config code:

The menus which are displayed for the navigation controls (SiteMapPath, Menu and TreeView) are described in

the sitemap file. Not all users will see the same menu. Only users who belong to the Librarian role will see the

menu items that are meant to be used by Librarians. These rules are defined in the sitemap file listed here:

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >

<siteMapNode url="RTLibrary.aspx" title="RT Library Home" description="RT

Library Home Page" roles="*">

<!-- set roles="*" so it shows up in the expanded menu -->

<siteMapNode url="login.aspx" title="Login" description="Login for " />

<siteMapNode title="Librarians" roles="Librarian">

<!-- roles="Librarian" is set in web.config for access security

but it also needs to be set here for menu trimming -->

<siteMapNode title="Member Admin" description="Administer member

information" roles="Librarian">

<siteMapNode url="~/Librarians/AddAdultMember.aspx" title="Add New Adult

Member" description="Add a new adult member"/>

<siteMapNode url="~/Librarians/AddJuvenileMember.aspx" title="Add New

Juvenile Member" description="Add a new juvenile member"/>

<siteMapNode url="~/Librarians/DisplayMember.aspx" title="Display Member

Info" description="Display member information"/>

</siteMapNode>

<siteMapNode title="Item Admin" description="Administer library items"

roles="Librarian">

<siteMapNode url="~/Librarians/AddNewItem.aspx" title="Add New Item"

description="Add a new item to the catalogue"/>

<siteMapNode url="~/Librarians/CheckInItem.aspx" title="Check In Item"

description="Check in an item"/>

<siteMapNode url="~/Librarians/CheckOutItem.aspx" title="Check Out Item"

description="Check out an item"/>

</siteMapNode>

</siteMapNode>

</siteMapNode>

</siteMap>

<?xml version="1.0" encoding="utf-8"?>

<configuration>

<system.web>

<authorization>

<allow roles="Librarian" />

<deny users="*" />

</authorization>

</system.web> </configuration>

Page 14: R Tanenbaum .Net Portfolio

Proper use of n-tier layer architecture – screenshot. Page 14

In this screen the status message, “Juvenile was successfully upgraded to adult”, is displayed to the user.

The action was implemented in the Business Layer with no changes required of the User Interface Layer.

Website user interface Windows forms user

interface

Business Layer – encapsulates implementation of business

rules. For example, juveniles are automatically converted to

adult status upon reaching age 18.

Data Access Layer – encapsulates all database calls. If there

is a change to the SQL stored procedure, only this layer is

affected.

SQL database – contains stored procedures and data tables.

Lib

rary

Da

ta E

nti

tie

s li

ke

Me

mb

er

or

Ite

m

ob

ject

s w

hic

h a

re c

om

mo

n t

o t

he

Da

ta A

cce

ss,

Bu

sin

ess

an

d U

ser

Inte

rfa

ce l

aye

rs.

User Interface Layer

Page 15: R Tanenbaum .Net Portfolio

Proper use of n-tier layer architecture – code sample. Page 15

The RT Library projects in all their phases implemented an n-tier architecture as laid out in the diagram above.

Phase 3 implemented a change to the business rules governing the display of juvenile members. The

requirements state that when the application displays a juvenile member, it should check to see if the member

is now at least 18 years-old and automatically convert the juvenile to adult status. This must happen

automatically without requiring any user interaction.

Therefore, this enhancement was implemented in the business layer without any changes to the user interfaces.

Here is the code from the business layer. The new code is highlighted in yellow.

public Member GetMember(short memberId, out string errString)

{

// Create a library data access object

Member myMember = null;

LibDataAccess lda = new LibDataAccess();

// Call the GetMember() method and pass in a member id.

try

{

myMember = lda.GetMember(memberId);

}

catch (LibraryException e)

{

formatErrorMessage(e.LibraryErrorCode, out errString);

return null;

}

catch (ArgumentOutOfRangeException)

{

errString = "Invalid member id.";

return null;

}

// Check here to see if this is a juvenile who should be promoted

if (myMember is JuvenileMember)

{

DateTime birth_date = ((JuvenileMember)myMember).BirthDate;

if (birth_date.AddYears(18) <= DateTime.Today)

{

// This juvenile had 18th birthday today or earlier

// Upgrade this juvenile to an adult

DateTime expr_date = DateTime.MinValue;

if (UpgradeJuvenileToAdult(memberId, out expr_date, out errString) < 0)

{

errString = "Failed to upgrade juvenile to adult";

return null;

}

// Now let's be really tricky and call ourselves

myMember = GetMember(memberId, out errString);

if (myMember == null)

{

return null;

}

// Successful upgrade and retrieval of new member

errString = "Juvenile was successfully upgraded to adult";

return myMember;

}

}

// Return the retrieved member

errString = "Success";

return myMember;

}

Page 16: R Tanenbaum .Net Portfolio

Using an AJAX client-side control – screenshot. Page 16

In the screenshot shown above, the item circled in yellow is implemented by an AJAX client-side control and

show activity while the server is processing the database request.

Using an AJAX client-side control – code sample. Page 16

Here is the code which implements the AJAX client-side control.

<!-- AJAX UpdateProgress Control should be outside of the UpdatePanel/!-->

<asp:UpdateProgress ID="CheckInUpdateProgress" runat="server">

<ProgressTemplate>

Item is being checked in ...

<asp:Image ID="CheckInProgressImage" runat="server"

ImageUrl="~/images/UpdateProgressActivity.gif" />

</ProgressTemplate>

</asp:UpdateProgress> <!-- End AJAX UpdateProgress Control /!-->

Page 17: R Tanenbaum .Net Portfolio

Use of CSS classes to unify a color scheme – screenshot. Page 17

The RT Library website uses a 3-color scheme on all of its pages to represent the status of library members:

Adult, Juvenile or Expired. The colors make it easy for the librarians to recognize a member’s status immediately

upon display. Instead of hard-coding these colors on every page they are defined in a single CSS file which is

referenced by the master page which is the template for all the other pages.

Use of CSS classes to unify a color scheme – code sample. Page 17

Here is how those colors are defined in the CSS file.

Here is how the CSS file is included in the master page.

And here is how the color is dynamically set when the page is running.

lblAddJuvenileStatus.Text = "NEW MEMBER<br />" + juvenileMemberString;

lblAddJuvenileStatus.CssClass = "juvenile";

<head runat="server">

<link href="~\RTLibrary.css" rel="Stylesheet" type="text/css" />

<title>RT Library Phase 3</title>

</head>

/* member background colors */

.expired { background-color: #FF99FF}

.adult { background-color: #66FF66}

.juvenile { background-color: #66CCFF}