This was a multi-phase project in the various .NET technologies using C# and Visual Studio. This set of projects was created to support the principal functions of a lending library’s day-to-day operations. TECHNOLOGIES USED: .NET with C#; Windows Forms Programming; Regular Expressions; ADO.NET; SQL Server 2000; Transact SQL (Stored Procedures); ASP.NET; ASP.NET Security; Web Services; XML; SOAP; WSE 3.0.
2. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Table of Contents
Library Project Overview.....................................................................................................................................3
Project Phase Overview.........................................................................................................................................4
Phase 1 - Windows Front-End Application.........................................................................................................5
Check In an Item:................................................................................................................................................5
Member Information............................................................................................................................................5
Check in an Item for a given member:................................................................................................................7
Juvenile Member Info..........................................................................................................................................9
Add New Adult...................................................................................................................................................10
Add New Juvenile..............................................................................................................................................11
Check Out an Item:............................................................................................................................................13
Phase 2 – Business & Data Access Tiers............................................................................................................15
Business Layer Code Samples...........................................................................................................................15
GetMyItems(MemberID)...............................................................................................................................15
AddMyMember(Member).............................................................................................................................16
Data Access Layer Code Samples.....................................................................................................................17
AddMember(AdultMember)..........................................................................................................................17
Stored Procedure usp_AddAdult...................................................................................................................18
GetItem(isbn, copyNumber)..........................................................................................................................19
Entities Code Samples.......................................................................................................................................20
Class Member................................................................................................................................................20
Class LibraryException..................................................................................................................................20
Phase 3 – Web Application..................................................................................................................................21
“Get Member Info” Page..................................................................................................................................22
“Member Info” Page.........................................................................................................................................22
“Get Book Info” Page.......................................................................................................................................26
“Book Info” Page..............................................................................................................................................28
Phase 4 – Web Services........................................................................................................................................29
Note: .................................................................................................................................................................29
A Web-based (ASP.NET) client was provided as the starting point for the front-end to communicate with the
web service. This was another separate implemenation of what I produced in Phase 3.................................29
Server-side Code Samples - The Service Class.................................................................................................30
Client-side Code Samples - The AddAdult Page...............................................................................................31
2
3. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Library Project Overview
Note: In Phase 3, a web-
based front end is designed
and implemented. Phase 4
goes further and provides
the functionality as a Web
Service.
Note: Library Entities is a
separate assembly
containing the classes that
define the various Entities
involved in the Library
Project, including Member,
Adult Member, Juvenile
Member, Item, Item
Dataset, LibraryException.
This was a multi-phase project in the various .NET technologies using C# and
Visual Studio.
This set of projects was created to support the principal functions of a lending library’s
day-to-day operations.
TECHNOLOGIES USED: .NET with C#; Windows Forms Programming; Regular
Expressions; ADO.NET; SQL Server 2000; Transact SQL (Stored Procedures);
ASP.NET; ASP.NET Security; Web Services; XML; SOAP; WSE 3.0.
3
4. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Project Phase Overview
Phase Objective Technologies
used
Phase 1 In this phase, the Database, Data Access Layer, .NET with C#;
and Library Entities were already provided. So this Windows Forms
phase involved the development of the front-end Programming;
Windows
layer (tier) and a business logic layer. Regular
Front-End • Design and develop an intuitive Windows Forms- Expressions.
Application based front-end application that that will provide a
librarian with a visual interface through which he or
she may perform the desired functions.
• Provide validation for all required fields, and
adequate error handling.
Phase 2 • Design and implement a Data Access tier using .NET with C#;
ADO.NET to replace the assembly provided in ADO.NET;
Phase 1. SQL Server
Business
• Provide Stored Procedures to be used by the new 2000;
& Data Access tier. The Data Access tier should not Transact SQL
Data Access contain any SQL statements. (Stored
Tiers • Retool Business tier to use new Data Access tier. Procedures).
• Design and implement a Library Entities
assembly to replace the assembly provided in
Phase 1.
Phase 3 • Create a web application that supports all the .NET with C#;
functionality required for Phase I and II of the ASP.NET;
Library project. ASP.NET
Web
• Provide Authentication/Security using ASP.NET Security.
Application Membership & Role Management.
Phase 4 • Take the library system to the next level – allow .NET with C#;
interoperability with other systems. ASP.NET;
• Create a Web service that calls into the business Web Services;
Web
layer. XML;
Services • Update the presentation (UI) layer to call the SOAP;
Web Service, and support previous project WSE 3.0.
functionality.
• Employ WSE 3.0 security using Certificates.
Signing, encryption and secure session are
required.
4
5. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Phase 1 - Windows Front-End Application
Overview:
Objective:
In this phase, the Database, Data Access Layer, and Library Entities were provided. So
this phase involved the development of the front-end layer (tier) and a business logic
layer.
• Design and develop an intuitive Windows Forms-based front-end application that that
will provide a librarian with a visual interface through which he or she may perform the
desired functions.
• Provide validation for all required fields, and adequate error handling.
Technologies used:
.NET & C#
Windows Programming
Regular Expressions
Check In an Item: MDI Interface
with Parent &
child forms.
Menu bar to
Navigate
through
various
functions
Status Bar to
communicate
Status and/or input
errors to the User.
In the above case, we tried to check in a book that was not on loan, and received an error
message. So we choose ISBN 100, Copy # 1 instead, and we can confirm or cancel the Check In.
Member Information Note the additional “New Adult Member” & “New Juvenile
Member” functions available in the Members Screen.
5
6. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
After we click
on Members …
… the default
function “Find
Member” is
displayed, and
a member is
found by
entering the
Card #….
FIND MEMBER:
Note: it could be an adult or a juvenile. We have 3 classes: Member, and then 2
derived classes AdultMember & JuvenileMember that inherit from Member.
private void btnFindMember_Click(object sender, EventArgs e)
{
//Check txtMemberID:
bool parseOK = Int16.TryParse(txtMemberID.Text, out intMemberID);
if (!parseOK)
{
DisplayStatus("Bad Number! Please enter a Valid Card Number.");
return;
} Instantiate Business Layer
// Business Layer
//Get Member: does all relevant
BusinessLayer bizLayer = new BusinessLayer(); error checking
member = bizLayer.GetMyMember(intMemberID, out resultOK); and passes the
if (!resultOK) result back
{ though variables
DisplayStatus(bizLayer.ErrorMessage); resultOK and
return; ErrorMessage.
}
The code then determines that Member ID 1 is an Adult Member
and displays the member info with the line:
ShowInterface(member, Action.ShowAdult);
}
… and the Member Info is displayed (in this case an Adult
Member) with <Check In> and <Check Out> functions shown …
6
7. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
DataGridView
control to manage
book loan
information. This
Member has 2
books on Loan.
Check in an Item for a given member:
In the above example, the User has clicked on <Check In> without properly selecting a book to check
in, so receives an error message.
After correcting the error, the User
tries again, and gets the option to
confirm or back out of the CheckIn.
7
8. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
CHECK IN AN ITEM FROM THE MEMBERS SCREEN:
private void btnCheckIn_Click(object sender, EventArgs e)
{
string msg;
string msg2; Handle selected rows
bool resultOK; in the DataGridView.
//
if (dgItems.SelectedRows.Count == 0)
{
DisplayStatus("Can't Check In - You need to Select an Item First!");
return;
}
foreach (DataGridViewRow dgvRow in dgItems.SelectedRows)
{
DataGridViewCellCollection coll = dgvRow.Cells;
//
//Handle nulls
//(happens if user has highlighted the new row at the end)
if (!(coll[0].Value == null))
{
int isbn = int.Parse(coll[0].Value.ToString());
short copy = short.Parse(coll[1].Value.ToString());
string title = coll[2].Value.ToString();
//
//Ask if User wants to Check it in:
msg = "Do you want to Check In: ";
msg += title + ", Copy # ";
msg += copy.ToString() + "?";
if (MessageBox.Show(msg, "Confirm Check In:",
MessageBoxButtons.OKCancel,
MessageBoxIcon.Question) == DialogResult.OK)
{
//Check it in:
Instantiate BusinessLayer bizLayer = new BusinessLayer();
Business resultOK = bizLayer.CheckInMyItem(isbn, copy);
Layer and use if (!resultOK)
{
it to check in
DisplayStatus(bizLayer.ErrorMessage);
the book.
return;
}
}
}
}
//Refresh the grid:
if (!BindGrid(intMemberID, out msg2))
{
DisplayStatus(msg2);
return;
}
}
8
9. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Juvenile Member Info
If we search for Member ID (card#) 10, we find that this is a juvenile Member …
The only Member
Info stored for a
Juvenile is Name,
Birthday, and the
Parent’s Member ID.
However this blue
panel also displays
the Parent’s member
info.
Notice that the
Parents card is
flagged as expired
No books on loan
for this Member.
9
10. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Add New Adult
Combobox
control
loaded from
XML file.
Input
Validation
using an
Error- When the
Provider mouse
control … hovers over
the Error-
Provider
… and the control, it
status bar. shows the
error
message,
which is
provided
using REGEX
(Regular
Expressions)
pattern
matching.
Set up Regular Expressions for Screen Validation, in the constructor
of the MembersForm class - MembersForm:
// set up validation regular expressions
this.txtFirstName.Tag = new PatternAndMessage(@"^[A-Z][a-z]{0,14}$",
"First Name must be all letters, first uppercase, " +
"all others lowercase, maximum 15 letters.");
PatternAndMessage is a helper object for associating a regular expression with an error message
Load the “States” combobox from the XML file in MembersForm_Load():
DataSet statesInfo = StatesData.GetStates();
// bind the State table in the dataset to the combobox
this.cbxState.DataSource = statesInfo.Tables["State"];
// tell the combobox to display the state Abbreviation
this.cbxState.DisplayMember = "Abbreviation";
// tell the combobox to use the abbreviation as the value
this.cbxState.ValueMember = "Abbreviation";
10
11. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Add New Juvenile
To add a new
Juvenile member,
first we need to
specify an adult
member who will
be responsible …
In the above case,
the User entered ID
10, which is that of
a juvenile, so the
input is rejected
with an error
message.
When an Adult ID is
entered, we get the
following screen …
Click <Add
Member>, and we
are then ready to
check out books for
the new member …
11
12. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
ADD NEW JUVENILE MEMBER:
private void btnAddNewMember_Click(object sender, EventArgs e)
{
…Validate input …
Instantiate a
try
Business layer
{
// Instantiate a Business Layer: object.
BusinessLayer bizLayer = new BusinessLayer();
//
//If Adult:
if (whatTypeOfMember == TypeOfMember.Adult)
{
…
} Instantiate and
//If Juvenile: populate a new
else JuvenileMember
{ object.
//Instantiate and Populate:
//(Assumes Thorough Validation first in the form)
JuvenileMember juv = new JuvenileMember();
juv.FirstName = this.txtFirstName.Text;
juv.LastName = this.txtLastName.Text;
juv.MiddleInitial = this.txtMiddleInitial.Text;
juv.AdultMemberID = (short)Convert.ToInt16(this.txtMemberID.Text);
juv.BirthDate = this.dateTimePicker1.Value;
//
//Add the Member: Add the Juvenile member
if (!bizLayer.AddMyMember(juv)) to the Database using the
{ Business Layer.
DisplayStatus(bizLayer.ErrorMessage);
return;
}
//
Display the new
action = Action.ShowJuvenile;
ShowInterface(juv, action); Juvenile member info.
}
}
catch (OverflowException exc) { DisplayStatus(exc.Message); }
catch (FormatException exc) { DisplayStatus(exc.Message); }
//Possible Exceptions from LibraryEntities:
catch (InvalidCastException exc) { DisplayStatus(exc.Message); }
catch (ArgumentNullException exc) { DisplayStatus(exc.Message); }
catch (ArgumentOutOfRangeException exc) { DisplayStatus(exc.Message); }
catch (Exception exc)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("General Exception Error: " + exc.Message);
if (!(exc.InnerException == null))
{
sb.AppendLine("Inner Exception: " + exc.InnerException.Message);
}
sb.AppendLine("Source: " + exc.Source);
DisplayStatus(sb.ToString()); Exception Handling
}
}
12
13. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
… And the new Juvenile Member Info is displayed
Click
<Check
Out>, to
check out
Books for
this
Member.
Check Out an Item:
If we choose
<Check Out> from
the Member
Screen, we get the
following dialog … We choose a
Book to check out
for the current
Member, and click
<Check Out> …
13
14. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
… then we get to confirm or back
out of the operation ….
… or if the book is in the system as
On Loan, the User is asked ….
Again, we can confirm or cancel.
private void btnCheckOut_Click(object sender, EventArgs e)
{ Instantiate a
CheckOutForm frmCheckOut = new CheckOutForm(intMemberID); new
frmCheckOut.ShowDialog(this); CheckOutForm
// and open it
string msg; modally.
if (!BindGrid(intMemberID, out msg)) Refresh the grid
{ to show newly
DisplayStatus(msg); checked out item.
}
}
14
15. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Phase 2 – Business & Data Access Tiers
Overview:
Objective:
• Design and implement a Data Access tier using ADO.NET to replace the assembly
provided in Phase 1.
• Provide Stored Procedures to be used by the new Data Access tier, which should not
contain any SQL statements.
• Retool Business tier to use new Data Access tier.
• Design and implement a Library Entities assembly to replace the assembly provided in
Phase 1.
Technologies used:
.NET & C#
ADO.NET
SQL Server 2000, Transact SQL (Stored Procedures)
Business Layer Code Samples
/// <summary>
/// The Business Layer is an intermediary layer between the Client and
/// Data Access Layers. It’s function is to encapsulate Business Logic.
/// </summary>
public class BusinessLayer
{
GetMyItems(MemberID)
/// <summary>
/// Interrogates the Data Access Layer
/// to return a Library ItemsDataSet object.
/// </summary>
public ItemsDataSet GetMyItems(short memberID, out bool resultOK)
{
// init:
ItemsDataSet MyItems = null; ItemsDataSet is a strongly typed
resultOK = false; Dataset object for populating the
// DataGridView. It is defined in
try separate assembly LibraryEntities.
{
// create a library data access object:
LibraryDataAccess lda = new LibraryDataAccess();
//
// Get Items object: Instantiate Data
MyItems = lda.GetItems(memberID); Access Layer …
resultOK = true;
}
catch … and use it to return
… etc …
a ItemsDataSet
return MyItems;
}
15
16. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
AddMyMember(Member)
public bool AddMyMember(Member m)
{ AdultMember &
// init: JuvenileMember are
bool resultOK = false; derived from the Member
bool isAdult; base class. All are
AdultMember adultMember; defined in separate
JuvenileMember juvenileMember; assembly LibraryEntities.
//
try
{
//
//check for null member:
if (m == null)
{
errorMessage =
"Could not Add Member. " +
"The Member object was null.";
return resultOK;
}
//
//Get What Kind Of Member:
adultMember = m as AdultMember;
if (!(adultMember == null)) { isAdult = true; }
else { isAdult = false; }
// Instantiate Data
//Create a library data access object: Access Layer …
LibraryDataAccess lda = new LibraryDataAccess();
Catch
//
any //Add the Member: … and use it to add
errors if (isAdult) { lda.AddMember((AdultMember)m); } the member to the
else { lda.AddMember((JuvenileMember)m); } database.
//
resultOK = true;
}
catch (LibraryException exc) LibraryException
{ is a custom Exception
errorMessage = GetLibraryErrorMessage(exc); object defined in
return resultOK; separate assembly
} LibraryEntities.
catch (Exception exc)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("General Exception Error: " + exc.Message);
if (!(exc.InnerException == null))
{
sb.AppendLine("Inner Exception: " + exc.InnerException.Message);
}
sb.AppendLine("Source: " + exc.Source); The Business Layer traps any
errorMessage = sb.ToString(); errors and exposes the result
return resultOK; back to the calling front end
} though the variable resultOK
return resultOK; and the ErrorMessage property.
}
16
17. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Data Access Layer Code Samples
AddMember(AdultMember)
/// <summary>
/// Adds specified Adult Member to the database. The AdultMember object that is
/// passed as a parameter must have all properties initialized except MemberID
/// & ExpirationDate which are populated with values returned by the database.
/// </summary>
public void AddMember(AdultMember adultMember) Instantiate a new
{ SqlConnection
try
{
using (SqlConnection cnn = new SqlConnection(
"Data Source=.;Initial Catalog=library;Integrated Security=True"))
{
using (SqlCommand cmd = Instantiate a new
new SqlCommand("usp_AddAdult", cnn)) SqlCommand
{ based on the
cnn.Open(); SqlConnection
cmd.CommandType = CommandType.StoredProcedure; and a stored
// procedure
SqlParameter prmFirstname = new SqlParameter();
Add Input prmFirstname.ParameterName = "@firstname";
Parameters to prmFirstname.Direction = ParameterDirection.Input;
prmFirstname.SqlDbType = SqlDbType.VarChar;
the SqlCommand
prmFirstname.Value = adultMember.FirstName;
object. cmd.Parameters.Add(prmFirstname);
//
… Other Input Parameters are added…
//
SqlParameter prmMember_no = new SqlParameter();
Add Output prmMember_no.ParameterName = "@member_no";
Parameters to prmMember_no.Direction = ParameterDirection.Output;
the SqlCommand prmMember_no.SqlDbType = SqlDbType.SmallInt;
cmd.Parameters.Add(prmMember_no);
object.
//
… Output Parameter @expr-date " is also added in like fashion …
Execute the //
command. int nrRowsAffected = cmd.ExecuteNonQuery();
ExecuteNonQuery //
means that it will
adultMember.MemberID = (short)cmd.Parameters["@member_no"].Value;
be returning no
adultMember.ExpirationDate =
rows.
Convert.ToDateTime(cmd.Parameters["@expr_date"].Value);
}
} The AdultMember object is updated with the info returned
} from the stored proc through the 2 output parameters.
catch (SqlException SqlEx)
{throw GetLibraryException(SqlEx); } Note that the first type of exception we try to
catch (Exception ex) catch is an SqlException. This will catch
{throw GetLibraryException(ex); } any error invoked by the RAISERROR
} statement in the stored procedure.
17
18. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Stored Procedure usp_AddAdult
-- Object: StoredProcedure [dbo].[usp_AddAdult] Script Date: 07/13/2009 03:08:35
USE [library]
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
-- ============================================= 8 Input Parameters
-- Author: Cormac Sharpe
-- Create date: June 26, 2009
-- Description: Adds an Adult Member to the Library
2 Output Parameters
-- =============================================
CREATE PROCEDURE [dbo].[usp_AddAdult]
@firstname varchar(15), @lastname varchar(15), @middleinitial varchar(1),
@street varchar(15), @city varchar(15), @state varchar(2), @zip varchar(10),
@phone_no varchar(13), @member_no smallint output, @expr_date datetime output
AS
BEGIN
SET NOCOUNT ON;
RAISERROR raises an State 118 flags an
--Validate Input; AddAdultFailed
sqlException, which is
----------------------------- caught in the ADO.NET code ErrorCode to
IF (@firstname is null) LibraryException.
OR (@lastname is null)
begin
Validate RAISERROR('usp_AddAdult: Incomplete Name - either @firstname or
Input @lastname was null.',16,118);
-- State 118 flags a AddAdultFailed ErrorCode to LibraryException
return -1
end
Also validated: IF (@street is null) OR (@city is null) OR (@state is null) (@zip is null) then RAISERROR.
--
set @expr_date = dateadd(year,1,getdate())
begin transaction
insert into dbo.member(firstname, lastname, middleinitial)
values (@firstname, @lastname, @middleinitial)
if @@error <> 0
Insert begin
Into rollback transaction
member RAISERROR('usp_AddAdult: An error occurred while adding an Adult
Table Member.',16,118);
-- State 118 flags a AddAdultFailed ErrorCode to LibraryException
return -1
Save the newly created MemberID
end
to the output parameter.
set @member_no = SCOPE_IDENTITY()
insert into dbo.adult(member_no, street, city, state, zip, expr_date)
values (@member_no, @street, @city,@state,@zip,@expr_date)
Insert if @@error <> 0
begin
Into
adult
rollback transaction
RAISERROR('usp_AddAdult: An error occurred while adding an Adult
Table
Member.',16,118);
-- State 118 flags a AddAdultFailed ErrorCode to LibraryException
return -1
end
commit transaction
END
18
19. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
GetItem(isbn, copyNumber)
/// <summary>
/// Returns an Item object that contains data about the item whose
/// ISBN and copy number are provided as parameters.
/// </summary>
/// <param name="isbn"></param>
/// <param name="copyNumber"></param>
public Item GetItem(int isbn, short copyNumber)
{
…
try
{
using (SqlConnection cnn = new SqlConnection(
"Data Source=.;Initial Catalog=library;Integrated Security=True"))
{
using (SqlCommand cmd =
new SqlCommand("usp_GetItem", cnn))
Add Input {
Parameters to the cnn.Open();
SqlCommand object. cmd.CommandType = CommandType.StoredProcedure;
THERE ARE NO //
OUTPUT //
PARAMETERS IN SqlParameter prmISBN = new SqlParameter();
THIS CASE. prmISBN.ParameterName = "@isbn";
prmISBN.Direction = ParameterDirection.Input;
prmISBN.SqlDbType = SqlDbType.Int;
prmISBN.Value = isbn;
cmd.Parameters.Add(prmISBN);
… Input Parameter @copy_no" is also added in like fashion …
Execute the
command.
ExecuteReader()
returns rows to the using (SqlDataReader reader = cmd.ExecuteReader())
SqlDataReader
{
object. //exactly 1 row should be returned
1 row is returned if (!(reader.Read()))
(the Select is based {
on a unique index).
…
}
The Item object is
created with the
row info returned Item myItem = new Item(myISBN, myCopyNumber, myTitle,
from the stored myAuthor, myMemberNumber, myCheckoutDate, myDueDate);
proc, and returned.
return myItem;
}
}
}
}
19
20. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Entities Code Samples
LibraryEntities is a separate assembly containing the classes that define the Entities involved in the
Library Project, including Member, AdultMember, JuvenileMember, Item, ItemDataset, LibraryException.
Class Member
/// <summary>
/// Represents a member of the library.
/// </summary>
[Serializable]
Base class from which AdultMember
public class Member
{ & JuvenileMember are derived.
//Fields:
private string city;
… etc …
// Member Constructor. Initializes the Member object.
public Member()
{
city = string.Empty; … etc … Properties to be exposed for the
}
Member class. All are read/write.
//Properties:
public string City
{
get { return city; }
set { city = value; } … etc …
}
}
Class LibraryException
/// <summary>
/// Custom exception for when a non-fatal error occurs in the Library App.
/// </summary>
[Serializable]
public class LibraryException : Exception Inherits from Exception.
{
//Fields:
private ErrorCode libraryErrorCode = ErrorCode.None;
… etc …
//
// Constructors:
public LibraryException(ErrorCode errorCode)
{libraryErrorCode = errorCode; }
… and a lot more constructor
public LibraryException(string message): base(message)
overloads …
{//do nothing - its handled by base class Exception. }
//
//Properties:
//Gets the value of the ErrorCode that was set when this exception was created.
//This value indicates the reason for the exception being thrown.
//If this value was not set explicitly, this property will return ErrorCode.None
public ErrorCode LibraryErrorCode
{
get { return libraryErrorCode; } … and other Properties …
}
}
20
21. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Phase 3 – Web Application
Overview:
Objective:
• Create a web application that supports all the functionality required for Phase I and II
of the Library project.
Technologies used:
.NET & C#; ASP.NET; Forms-based authentication;Security using ASP.NET Membership
& Role Management.
All pages use a common
theme and Master Page.
Hypertext based
Menu system
Security using
ASP.NET
Membership & Role
Management. Only
Users belonging to
the “Librarian” role
can Log in.
WEB.CONFIG
<?xml version="1.0"?>
<configuration> Note authorization in
<appSettings/> Web.config - Anyone can
<connectionStrings/> access the Website, but all
important functionality is
<system.web>
restricted to “Librarian”
<authorization> role members.
<allow roles="Librarian" />
<deny users="*" />
</authorization>
</system.web>
</configuration>
21
22. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
“Get Member Info” Page
If we enter card# 1
and click <Get Member
Info>, the following
code runs …
Session["MemberObject"] = member;
Response.Redirect(@"~/Operations/MemberInfo.aspx"); Save member object as
session info and redirect to
the MemberInfo page.
“Member Info” Page
public partial class Operations_MemberInfo : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
…
if (!Page.IsPostBack) Only do these actions if this page is opening
{ fresh, i.e. not posting back from the server.
…
if ((Session["MemberObject"] != null))
{ member = (Member)Session["MemberObject"]; } Retrieve member object
// from session info.
if (member is AdultMember) { ShowAdult(); }
else // Member is a Juvenile:
{
juv = (JuvenileMember)member;
//If Juvenile over 18:
22
23. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
if (juv.BirthDate.AddYears(18) <= DateTime.Today)
{
//Update Juvenile to Adult:
BusinessLayer biz = new BusinessLayer();
resultOK = biz.UpdateToMyAdult(juv.MemberID);
A Juvenile
member who … Check Result with: if (!resultOK) etc …
is over 18 is //Re-retrieve member - is now an adult:
automatically BusinessLayer biz1 = new BusinessLayer();
updated to member = biz1.GetMyMember(juv.MemberID, out resultOK);
being an Adult … Check Result with: if (!resultOK) etc …
member.
ShowAdult();
string msg = string.Empty;
msg += "This member is over 18, but was in the system as a ";
msg += "juvenile. The member was updated to an Adult. ";
DisplayMessage(msg);
}
else { ShowJuvenile(); }
}
}
…
}
In this case we had entered card# 1, and
we find that this is an Adult Member …
Its not shown on this screen, but if the
card is over 1 year old, then the card is
flagged with Card is Expired, and the
user is given the opportunity to renew
it with a <Renew Membership>
button, which appears only in that
case. Here’s the code:
If
(DateTime.Parse(this.lblExpirationDat
e.Text) < DateTime.Today)
{
this.lblExpired.Visible = true;
this.lblExpiredFlag.Visible = true;
this.btnRenew.Visible = true;
this.btnCheckOut.Enabled = false;
}
If we enter ISBN 1, Copy#1, and then
click <Check Out>, we get an option to
Confirm or Cancel …
When we click on <OK> …
23
24. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
btnOK runs when the user
protected void btnOK_Click(object sender, EventArgs e) confirms the Check out.
{
Item item;
string msg;
//
//Retrieve the Item from Session:
if (Session["ItemObject"] != null)
Retrieve Item object from
{
item = (Item)Session["ItemObject"]; Session.
} (Earlier when <Check Out>
else was clicked,
{ btnCheckOut_Click ran,
DisplayMessage("Error retrieving the Item."); populating an Item object,
SetCheckOut(false); which it then saved to
return; Session)
}
//
//If Item is on Loan:
if (!(item.MemberNumber == 0))
{
// Check it In first:
BusinessLayer biz = new BusinessLayer();
resultOK = biz.CheckInMyItem(item.ISBN, item.CopyNumber);
if (!resultOK)
{
DisplayMessage(biz.ErrorMessage);
SetCheckOut(false);
return;
}
}
//
//Check it out:
BusinessLayer biz2 = new BusinessLayer(); Check out the Item
resultOK = biz2.CheckOutMyItem( (copy of a book).
short.Parse(this.lblMemberID.Text),
item.ISBN, item.CopyNumber);
if (!resultOK)
{
if (biz2.ErrorMessage == "FourBooksAlreadyCheckedOut")
{ Enforce a
msg = "Four Books are Already Checked Out. "; maximum of 4
msg += "n"; items on loan at
msg += "Four is the maximum allowed."; a time.
DisplayMessage(msg);
}
else
{
DisplayMessage(biz2.ErrorMessage);
}
SetCheckOut(false);
return;
}
//
//Refresh Grid: Refresh the
grid to display
the new item on 24
loan.
25. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
this.GridView1.DataBind();
//
SetCheckOut(false);
//
DisplayMessage("Check Out Complete!");
}
… the Item is added to the
grid, and the Check Out is
confirmed.
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
isbn = int.Parse(this.GridView1.SelectedRow.Cells[1].Text); Selecting a book in
copy = short.Parse(this.GridView1.SelectedRow.Cells[2].Text); the grid checks it in.
//
BusinessLayer bizLayer = new BusinessLayer();
resultOK = bizLayer.CheckInMyItem(isbn, copy);
if (!resultOK)
{
DisplayMessage(bizLayer.ErrorMessage);
return;
}
//Refresh Grid:
this.GridView1.DataBind();
}
25
26. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
“Get Book Info” Page
User has the choice to
just get the Book Info,
or do so while also
adding a new copy of
the book.
Click <Get Book> …
26
27. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
public partial class Operations_GetBook : System.Web.UI.Page
{
…
protected void btnGetBook_Click(object sender, EventArgs e)
{
//Get Book:
BusinessLayer bizLayer = new BusinessLayer();
book = bizLayer.GetMyBook( GetMyBook creates and
int.Parse(this.txtISBN.Text), populates a Book object, based
out resultOK); on the inputted ISBN.
if (!resultOK)
{
if (bizLayer.ErrorMessage == "BookNotFound")
{
//give user option to add new Book or back out:
DisplayStatus("This Book does not yet exist. Do you want to add it?";);
//Show Ok & Cancel buttons
SetNewBookOption(true);
return;
}
else The Book was not found. User is
{ given the option to add it to the
DisplayStatus(bizLayer.ErrorMessage); system.
return;
}
}
// Save Book object to Session.
//if the code gets this far, then ....
//Save the Book in Session:
Session["BookObject"] = book;
if (this.chkNewCopy.Checked)
{ Save the boolean
Session["BookAddNewCopy"] = true; BookAddNewCopy to Session.
}
else
{
Session["BookAddNewCopy"] = false;
}
Response.Redirect(@"~/Operations/BookInfo.aspx"); Redirect to BookInfo
} page.
protected void btnOK_Click(object sender, EventArgs e)
{
Session["NewBookISBN"] = this.txtISBN.Text;
Response.Redirect(@"~/Operations/AddNewBook.aspx"); Redirect to AddNewBook
} page if User chose to
add a book that was not
} found.
… and we are presented with the book info for ISBN #1 …
27
28. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
“Book Info” Page
Since we chose in the
previous screen to add
a new copy, copy #20
has been added …
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
if ((Session["BookObject"] != null))
Retrieve Book object
{
book = (Book)Session["BookObject"]; from Session.
}
}
this.lblAuthor.Text = book.Author;
this.lblCover.Text = book.Cover; Populate the page.
… etc …
// Retrieve the boolean
if ((bool)Session["BookAddNewCopy"]) BookAddNewCopy from Session.
{
newCopyNo = (short)(book.Max_copy_no + 1); This indicates whether the user
// chose to also add a new copy of
//Add New Copy: the book.
BusinessLayer bizLayer = new BusinessLayer();
resultOK = bizLayer.AddMyCopy(book.ISBN, newCopyNo, book.Title_no);
… Check Result with: if (!resultOK) etc …
AddMyCopy, and flag this, if the
//
this.lblMaxCopyNo.Text = newCopyNo.ToString(); user chose to add a new copy.
lblMaxCopyUpdated.Visible = true;
//
msg = "A New Copy "(Copy Nr " + newCopyNo.ToString() + ") has been added.";
DisplayStatus(msg); }}
28
29. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Phase 4 – Web Services
Overview:
Objective:
• Take the library system to the next level – allow interoperability with other systems.
• Create a Web service that calls into the Business Layer.
• Update the Client (UI) layer to call the Web Service, and support previous project
functionality.
• Employ WSE 3.0 security using Certificates. Signing, encryption and secure session are
required.
Technologies used:
.NET; C#; ASP.NET; Web Services; XML; SOAP; WSE 3.0
Web Client
Sample Page.
Note:
A Web-based
(ASP.NET) client
was provided as
the starting
point for the
front-end to
communicate
with the web
service. This
was another
separate
implemenation
of what I
produced in
Phase 3.
29
30. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Server-side Code Samples - The Service Class
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using SFLibraryBusiness;
using SFLibraryEntities;
using System.Xml.Serialization;
using System.Xml; The Web Service
using Microsoft.Web.Services3; supports the
Basic Profile.
[WebService(Namespace = "http://setfocus.com/libraryphase4")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[Policy("CertificatesPolicy")] Use WSE 3.0
public class Service : System.Web.Services.WebService security with
{ Certificates.
Derive Service class from
System.Web.Services.WebService
/// <summary>
/// Gets the member object using a member number or id.
/// </summary>
/// <param name="memberNumber">Member number.</param>
/// <returns>Populated member object with data.</returns> GetMember returns the base
[WebMethod] class Member. To tell the
[XmlInclude(typeof(AdultMember))] client and web service to
[XmlInclude(typeof(JuvenileMember))] handle the sub-classes
public Member GetMember(short memberNumber) correctly, we use the
{ XmlInclude attribute.
try
{
Library lib = new Library();
Member m = lib.GetMember(memberNumber); The Web Service
return m; simply instantiates
} and calls into the
Business Layer.
catch (LibraryException libex)
{
throw new SoapException(libex.Message, SoapException.ClientFaultCode, libex);
}
}
Re-throw any LibraryException as a SoapException.
… and the other Web Methods are very similar …
}
30
31. .NET Library Project Spring/Summer 2009 - Cormac Sharpe
Client-side Code Samples - The AddAdult Page
public partial class AddAdult : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack) If this is the page opening 1st time (not a
{ postback from the server), then load the
this.LoadStates(); States dropdown box from the xml file.
}
}
protected void addAdultButton_Click(object sender, EventArgs e)
{
if (!Page.IsValid)
{ return; }
try
{
// Populate new adult object
AdultMember newAdultMember = new AdultMember();
newAdultMember.FirstName = firstNameTextBox.Text;
… etc …
// Attempt to add new adult member Implement WSE 3.0 security
ServiceWse lib = new ServiceWse(); using Certificates.
lib.SetPolicy("CertificatesPolicy");
newAdultMember = lib.AddAdultMember(newAdultMember);
short memberID = newAdultMember.MemberID;
… and the service (ServiceWse) is invoked,
which in turn calls into the Business Layer.
// Redirect to the GetMemberInfo page and pass the new member id.
// false is passed to surpress the internal call to the Response.End
// Additional details at: http://support.microsoft.com/kb/312629/EN-US/
Response.Redirect(string.Format("GetMemberInfo.aspx?MemberID={0}",
memberID.ToString()), false);
}
catch (Exception ex)
{statusLabel.Text = "Error: <br> " + ex.Message;}
Redirect to the GetMemberInfo page passing the new member id.
In the GetMemberInfo class the MemberID will be retrieved as follows:
//populate the textbox with the value
this.memberNoTextBox.Text = Request.QueryString["MemberID"];
31