R Tanenbaum .Net Portfolio


Published on

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

  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

R Tanenbaum .Net Portfolio

  1. 1. Robert Tanenbaum rtanenbaum@att.net 732.819.7533
  2. 2. CONTENTS: Demonstrate the use of polymorphism – screenshot. Page 3 Demonstrate the use of polymorphism – code sample. Page 4 Use of a strongly typed dataset – screenshot. Page 5 Use of a strongly typed dataset – code sample. Page 6 Showing data entry field validation – screenshot. Page 7 Showing data entry field validation – code sample. Page 8 Use of ADO.Net and T-SQL stored procedures – screenshot. SQL Page 9 Use of ADO.Net and T-SQL stored procedures – code sample. SQL Page 10 Demonstrate role-based security and navigation – screenshot. based Page 12 Demonstrate role-based security and navigation – code sample. based Page 13 Proper use of n-tier layer architecture – screenshot. tier Page 14 Proper use of n-tier layer architecture – code sample. tier Page 15 Using an AJAX client-side control – screenshot. side Page 16 Using an AJAX client-side control – code sample. side Page 16 Use of CSS classes to unify a color scheme – screenshot. Page 17 Use of CSS classes to unify a color s scheme – code sample. Page 17
  3. 3. 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.
  4. 4. 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. 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; } Here is the code for the event handler when tabbing out of the member identifier text box: private void memberIdTextBox_Validating(object sender, CancelEventArgs e) { lookupButton_Click(sender, e); } 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.
  5. 5. 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.
  6. 6. 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. 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) } } In just 3 simple statements highlighted in yellow above, the dataset is created and filled.
  7. 7. 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.
  8. 8. 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. 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"); } } } } 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.
  9. 9. 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.
  10. 10. 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. 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); 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);
  11. 11. 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.
  12. 12. 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.
  13. 13. 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: <?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <authorization> <allow roles="Librarian" /> <deny users="*" /> </authorization> </system.web> </configuration> 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>
  14. 14. 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. User Interface Layer Website user interface Windows forms user interface objects which are common to the Data Access, Library Data Entities like Member or Item Business and User Interface layers. 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.
  15. 15. 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; }
  16. 16. 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 /!-->
  17. 17. 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. /* member background colors */ .expired { background-color: #FF99FF} .adult { background-color: #66FF66} .juvenile { background-color: #66CCFF} Here is how the CSS file is included in the master page. <head runat="server"> <link href="~RTLibrary.css" rel="Stylesheet" type="text/css" /> <title>RT Library Phase 3</title> </head> And here is how the color is dynamically set when the page is running. lblAddJuvenileStatus.Text = "NEW MEMBER<br />" + juvenileMemberString; lblAddJuvenileStatus.CssClass = "juvenile";