The library project involves developing Windows, ASP.NET, and WCF applications across four phases, starting with a Windows front end for library functions and moving to a web application, then implementing data access using LINQ and ADO.NET before creating a WCF service that utilizes security to allow interoperability with other library systems.
1. ® Library Project
As Implemented By: Alan P. Weir
apweir@cox.net 860-649-7603
2. ® uses a progressive Library Project
consisting of four distinct phases throughout
the curriculum.
The library project is an intensive, hands-on, project where knowledge
and experience is gained in the key components necessary to roll out
Windows, ASP.Net, and WCF applications.
It encompasses:
• Developing solutions for diverse programming scenarios in C#
• Developing queries using MS SQL Server 2008 Transact-SQL
(T-SQL)
• Using C#, LINQ and ADO.NET to define and implement secure
middle-tier components
• Creating and deploying XML Web Services using ASP.NET and
Windows Communication Foundation (WCF)
• Consuming Web Services from Windows forms and ASP.NET
web applications
• Creating Deployment projects for .NET applications using
Microsoft’s MSI packages
3. Phase I—
Create a Windows front end User
A database has been
created to support the
principal functions of
a lending library’s day-
today operations: adding
new members (adult and
juvenile) and checking
books in and out. An
assembly has been created
that contains classes and
interfaces that provide
access to the database for
these functions. What
is needed is a Windows
Forms-based front-
end application that
will provide a librarian
with a visual interface
through which he or she
may perform the desired
functions.
4. Code Showing the Add Juvenile Form
public partial class frmStart : Form
{
#region Add Juvenile
/// <summary>
/// Tool Strip Menu - Add Juvenile Member
/// Button Click Add Juvenile
/// </summary>
/// <param name=”sender”></param>
/// <param name=”e”></param>
private void addJuvenileToolStripMenuItem_Click(object sender, EventArgs e)
{
UtilityMethods ja = new UtilityMethods();
ja.frmJuvenileAddShow();
}
private void btnAddJuvenile_Click(object sender, EventArgs e)
{
UtilityMethods ja = new UtilityMethods();
ja.frmJuvenileAddShow();
}
#endregion //Juvenile add
/// <summary>Utility Methods</summary>
public class UtilityMethods
{
#region Show Forms
/// <summary>Show Juvenile Add</summary>
public void frmJuvenileAddShow()
{
frmAddJuvenile frm = new frmAddJuvenile();
frm.Show();
}
}
7. Add Juvenile Member Code
#region Add Juvenile member Add Button Click if (response == DialogResult.OK)
/// <summary>Add Juvenile Member Add Button {
Click</summary> txtAdultID.Text = string.Empty;
/// <param name=”sender”></param> txtFirstName.Text = string.Empty;
/// <param name=”e”></param> txtMiddleInitial.Text = string.Empty;
private void btnAddJuvenile_Click(object sender, txtLastName.Text = string.Empty;
EventArgs e) txtAdultFirstName.Text = string.Empty;
{ txtAdultLastName.Text = string.Empty;
try txtState.Text = string.Empty;
{ txtStreet.Text = string.Empty;
//Create a new Instance of Jevenile member txtCity.Text = string.Empty;
//and populate some of the fields with the txtZipCode.Text = string.Empty;
information provided in the text boxes txtPhone.Text = string.Empty;
}
var myJevMember = new Member(); else
{
myJevMember.firstname = this.Close();
txtFirstName.Text; }
if (txtMiddleInitial.Text == null) }
{ catch (LibraryException ex)
txtMiddleInitial.Text = “ “; {
} switch (ex.LibraryErrorCode)
myJevMember.middleinitial = {
tMiddleInitial.Text[0]; case ErrorCode.MissingAdultMember:
myJevMember.lastname = txtLastName.Text; tssMessage.Text =”Missing
myJevMember.adult_member_no = mId; AdultMember Failure”;
myJevMember.birth_date = break;
dateTimePicker1.MinDate; case ErrorCode.NoSuchMember:
tssMessage.Text = “Adult Member
BusinessLayer bl = new BusinessLayer(); Not Found”;
bl.AddJuvenileMember(myJevMember); break;
case ErrorCode.None:
DialogResult response = tssMessage.Text = ex.Message;
MessageBox.Show(string.Format(“{0} ‘s new break;
member number is {1}”, default: tssMessage.Text =
myJevMember.firstname, ex.Message;
myJevMember.member_no.ToString()), break;
“Juvenile Added”, }
MessageBoxButtons.OKCancel); }
catch (Exception ex)
{
tssMessage.Text = ex.Message;
}
}
#endregion Add Juvenile member Add Button Click
8. Phase II—
Design and Create the Business and Data
Requirements:
• Develop code that is easily maintainable.
• Provide adequate error handling.
• Use database-programming techniques that provide maximum
programming flexibility and control while minimizing resource
utilization.
• Work with your instructor who will act as the project DBA for any
required SQL help.
9. Required Functionality:
In Phase 1 of this ongoing project, you Focus your efforts on the following:
were provided with an assembly that • Add Adult: Rows are added to both the
encapsulated all the data access logic for member table and the adult table.
your application. The assembly in Phase 1
• Add Juvenile: Verification that the
employed ADO.NET to provide access to
sponsoring adult member’s record exists
the library database. It did not, however, use
(and is unexpired) must be performed.
any stored procedures, which could have
made database operations more efficient. In • The juvenile’s age should be verified that
Phase 2, you are to design and implement it is an acceptable age of a juvenile. Rows
your own business and data access tiers. Use are added to both the member table and
stored procedures which must be commented the juvenile table.
thoroughly and your code should not contain • Checkout item: Verification that item
any SQL statements. exists and is not already on loan must be
performed.
You were also provided an assembly that
• Verification that item is loanable must be
contained business entity classes needed
performed. Row is added to loan table.
for the project (e.g., Item, ItemsDataSet,
Update copy table’s on_loan field to ‘Y’.
Member, etc.). You must not use either of the
assemblies that were provided to you in your • Checkin item: Verify that the item exists
Phase 2 project. You must implement the and is on loan. Delete row from loan table.
business entity classes yourself. You are not Add row to loanhist table. Update copy
obligated to use the same interface that the table’s on_loan field to ‘N’.
data access object in the assembly provided The data access tier has to be stateless.
in Phase 1 employed. If you wish to redesign Stateless means that the data access class
this interface, you may do so, provided that must not maintain variable state between
all required functionality is supported. method calls. Variable state should be kept
to local variables.
In Phase 1 of this ongoing project,
verification that an item presented for Remember to treat operations that involve
checkout is loanable was not a requirement. multiple tables as transactions, and
In this phase, you must perform that validate against null inputs in each relevant
verification and prevent an item that is not procedure.
loanable from being checked out.
10. Add Juvenile Stored Procedure
USE [library] BEGIN
GO RAISERROR(‘AdultMember Not
Found’, 11, 2)
SET ANSI_NULLS ON RETURN
GO
SET NOCOUNT ON;
SET QUOTED_IDENTIFIER ON
GO BEGIN TRANSACTION
INSERT dbo.MEMBER
IF OBJECT_ID(‘[dbo].[uspJuvenileMemberI (
nsert]’) IS NOT NULL Lastname
DROP PROCEDURE ,Firstname
[dbo].[uspJuvenileMemberInsert] ,Middleinitial
GO )
VALUES (
CREATE PROCEDURE @lastname
[dbo].[uspJuvenileMemberInsert] ,@firstname
@member_no smallint OUTPUT ,@middleinitial
,@lastname varchar (15) )
,@firstname varchar (15) IF @@error <> 0
,@middleinitial char (1) = NULL BEGIN
,@adultmemberno smallint ROLLBACK TRAN
,@birthdate datetime RETURN
AS END
BEGIN SET @member_no = Scope_Identity()
IF INSERT dbo.juvenile(
@lastname IS NULL OR member_no
@firstname IS NULL OR ,adult_member_no
@adultmemberno IS NULL OR ,birth_date
@birthdate IS NULL )
BEGIN VALUES ( @member_no
RAISERROR(‘You Must provide ,@adultmemberno
Member Info’,11,1) ,@birthdate
RETURN )
END IF @@error <> 0
BEGIN
IF NOT EXISTS ROLLBACK TRAN
(SELECT * FROM dbo.adult WHERE RETURN
member_no = @adultmemberno) END
COMMIT TRANSACTION
END
11. Retrieve Books on Loan By Member—
Load a LINQ Dataset
Business Layer Code
/// <summary>Get Books on loan by members</summary>
/// <param name=”myMember”></param>
/// <returns></returns>
public AW.LibraryEntitiesLINQ.ItemsDSLINQ
getItems(short myMember)
{
//Create a Library data access object
DataAccessLINQcode dalc = new DataAccessLINQcode();
return dalc.getItems(myMember);
}
Data Access Layer
/// <summary>Data Access Class </summary>
#region Data Access Class
public class DataAccessLINQcode
{
/// <summary>Get The Items Data Set Info</summary>
/// <param name=”member_no”></param>
/// <returns>Books on Loan for this Member</returns>
public ItemsDSLINQ getItems(short member_no)
{
try
{
var itemsDSL = new ItemsDSLINQ();
using (ItemsTALINQ ita = new ItemsTALINQ())
{
ita.Fill(itemsDSL.ItemsLINQ, member_no);
}
return itemsDSL;
}
catch (SqlException ex)
{
if (ex.State == 1) {
throw new LbraryException(ex.ToString(),
ErrorCode.MissingAdultMember, ex);
}
else }
throw new LibraryException(ex.ToString(),
ErrorCode.GenericException, ex);
}
}
}
12. Phase III—
Web Application (ADO.NET, ASP.NET, LINQ,
AJAX Controls)
Requirements:
Create a web application that supports all the functionality required for
Phase I and II of the Library project.
Additional requirements: you must add all necessary records for the
• When displaying an adult’s information, new ISBN and a new copy number 1 for
the application should detect if the card is that ISBN.
expired and give the librarian a chance to • On the Member Information page the
renew the card. Librarian must be able to design must be altered to use two AJAX
choose whether or not to renew the card. controls, the Update Panel control and
The renewal date is today plus one year. the Update progress control. The Update
Members cannot check out books if the Panel control will need to be placed on
card is expired. the form and the grid view that displays
• When dealing with juveniles, the checked out items will then be placed
application should detect if the juvenile within the Update Panel control. The check
is 18 years old or older and convert in functionality will reside within the panel
the member to an adult (row deleted and when an item is checked in a postback
in the juvenile table, row added to the for the entire page should not be triggered.
adult table). This operation is not at the Only the information within the Update
discretion of the librarian; i.e. the upgrade Panel should be updated. Additionally, the
must take place automatically and the Update Progress control should display
librarian must be notified that the upgrade the progress of the check in action. (If your
has taken place. project does not currently have a page
that displays the member’s information,
• Overdue books, shown in any display, must
with a grid that displays the items that are
be highlighted.
checked out, one will need to be added.
• The librarian must be able to enter a new The librarian should be able to select a row
book into the database. If the ISBN already and click a check in button to check the
exists in the database, all that is needed is item back into the library).
to add a record for a new copy number. If
• Use hyperlinks to navigate between pages.
the ISBN does not yet exist in the database,
13. Add Member—both Adult and Juvenile—
using LINQ–Data Access Code
///<summary>Data Access Class </summary> #region Data Access Class
#region Data Access Class public class DataAccessLINQcode
public class DataAccessLINQcode ,myJuvenileMember.adult_member_no
#region Add Member - Adult and Juvenile ,myJuvenileMember.birth_date);
/// <summary>Add Member</summary>
public AW.LibraryEntitiesLINQ.Member if (tempID.HasValue)
addMember(Member myMember) {
{ myJuvenileMember.member_no =
var ldc = new (short)tempID
AW_LibraryObjectModelDataContext(); }
short? tempID = myMember.member_no else
ldc.AdultInsert(ref tempID {
,myMember.lastname throw new
,myMember.firstname LibraryException(ErrorCode.MemberNumberCame
,myMember.middleinitial BackNull, “Member No Came Back Null”);
,myMember.street }
,myMember.city return myJuvenileMember;
,myMember.state }// end Method Add uvenile
,myMember.zip #endregion //Add Member - Adult and Juvenile
,myMember.phone_no);
if (tempID.HasValue)
{
myMember.member_no = (short)tempID;
}
else
{
throw new LibraryException
(ErrorCode.MemberNumberCameBackNull,
“Member No Came Back Null”);
}
return myMember;
} //method add Adult
/// <summary>Add Juv’y Member</summary>
public AW.LibraryEntitiesLINQ.Member
addMemberJev(Member myJuvenileMember)
{
var ldc = new
AW_LibraryObjectModelDataContext();
short? tempID = myJuvenileMember.member_no;
ldc.JuvenileInsert(ref tempID
,myJuvenileMember.firstname
,myJuvenileMember.lastname
,myJuvenileMember.middleinitial
14. Retrieve Member Information—
Highlighted Over Due Book(s)
protected void // update the CheckIn arguments
booksGridView_RowDataBound(object sender, Int32 isbn = (Int32)row[“isbn”];
GridViewRowEventArgs e) Int16 copyNo = (Int16)row[“copy_no”];
{ LinkButton cmdCheckIn =
if (e.Row.RowType != (LinkButton)e.Row.FindControl(“cmdCheckIn”);
DataControlRowType.DataRow) return; cmdCheckIn.CommandArgument =
try String.Format(“{0}|{1}”, row[“isbn”],
{ row[“copy_no”]); // 1|3
DataRowView row = e.Row.DataItem as }
DataRowView; catch
BusinessLayer bl = new BusinessLayer(); {
If (bl.IsOverDue((DateTime)row[“due_date”])) tssMessage.ForeColor = Color.Red;
{ tssMessage.Text = (“An unexpected error occured”);
e.Row.ForeColor = System.Drawing.Color.Red; }
tssMessage.ForeColor = }
system.Drawing.Color.Red;
tssMessageExpired.Visible = true;
tssMessageExpired.Text = “Book is Over Due”;
}
}
15. Phase IV—
WCF Service
Our library system rollout has been very successful. As the potential
to acquire libraries and creating partnerships with others increases,
we see the need to take the library system to the next level—allow
interoperability with other systems. With the success on the library
system thus far, we are tasking you to provide a proof of concept
implementation that utilizes Web services. Use Windows
Communication Foundation (WCF) to implement the service. To
provide the proof of concept system, you must implement a system
that uses Web services to offer access to the business layer. Due to the
possibility of utilizing the service between our own systems and those
of our partners, security must be employed. Use your existing
presentation front-end for the client layer.
Requirements:
• Create a WCF service that calls into the business layer. Do not re-write
the business layer. Simply have the service call into the layer.
• Update the presentation (UI) layer to call the WCF service. This will
require changing some namespaces and references to accommodate
the service.
• The WCF Service must be implemented with or support the following:
– WCF Service Library project
– WCF Service Website
– Uses the WCF Service Library project
– Uses WsHttpBinding
– Authentication using ASP.NET membership—must be a member
of the LibraryPartner role
– Authorization using ASP.NET roles—LibraryPartner role
– Use PrinciplePermission to secure service operations
– Use DataContracts for entities
– Support previous project functionality
16. WEB Service—
Interface and Contracts
namespace AWPhase4ServiceLibrary /// <summary>Retrieve book Info</summary>
{ /// <param name=”ISBN”></param> <param
/// <summary>WEB Service</summary> name=”Copy_no”></param>
[ServiceContract(Namespace = /// <returns>Book Info</returns>
“http://AlanWeir.com/”)] [OperationContract]
public interface IAWPhase4Service [FaultContract(typeof(LibraryFaultErrors))]
{ Item GetItemInformation(int ISBN, short Copy_no);
/// <summary>Contract</summary>
/// <param name=”ISBN”></param> /// <summary>Add Book</summary>
/// <param name=”Copy_no”></param> /// <param name=”myTCIView”></param>
[OperationContract] /// <returns></returns>
[FaultContract(typeof(LibraryFaultErrors))] [OperationContract]
void CheckBookIn(int ISBN, short Copy_no); [FaultContract(typeof(LibraryFaultErrors))]
AW.LibraryEntitiesLINQ.TCIViews
/// <summary>Retrieve Member Info</summary> addBook(TCIViews myTCIView);
/// <param name=”memberID”></param>
// <param name=”rv”></param> /// <summary>Check book out</summary>
/// <returns></returns> /// <param name=”memberID”></param>
[OperationContract] /// <param name=”itemISBN”></param>
[FaultContract(typeof(LibraryFaultErrors))] /// <param name=”itemCopy”></param>
Member getMember(short memberID, ref int rv); [FaultContract(typeof(LibraryFaultErrors))]
[OperationContract]
/// <summary>Add Adult Member</summary> void CheckOutItem(short memberID, int itemISBN,
/// <param name=”myMember”></param> short itemCopy);
[OperationContract] }
[FaultContract(typeof(LibraryFaultErrors))] }
Member addMember(Member myMember);
/// <summary>Add Juvenile Member </summary>
/// <param name=”myJuvMember”></param>
[OperationContract]
[FaultContract(typeof(LibraryFaultErrors))]
Juvenile addJuvenileMember(Juvenile
myJuvMember);
/// <summary>Get Copy No for Book
Add</summary>
/// <param name=”ISBN”></param>
/// <returns>Copy Number</returns>
[OperationContract]
[FaultContract(typeof(LibraryFaultErrors))]
CopyNumber getCopyNumber(int ISBN);
17. Web Service (typical)—
Phase IV Visual Studio Solution
namespace AWPhase4ServiceLibrary
{
/// <summary>Web Service
AWPhase4</summary>
public class AWPhase4Service : IAWPhase4Service
{
/// <summary>Check Book In</summary>
[PrincipalPermission(SecurityAction.Demand,
Role = “LibraryPartner”)]
public void CheckBookIn(int ISBN, short Copy_no)
{
try {
BusinessLayer bl = new BusinessLayer();
bl.CheckInItem(ISBN, Copy_no);
}
catch (LibraryException ex) {
var lfe = new LibraryFaultErrors();
lfe.Message = ex.Message;
lfe.LibraryErrorCode = ex.LibraryErrorCode;
throw new FaultException<LibraryFaultErrors>(lfe,
lfe.Message);
}
}
/// <summary>Check Book Out</summary>
[PrincipalPermission(SecurityAction.Demand,
Role = “LibraryPartner”)]
public void CheckOutItem(short memberID, int
ISBN, short copy_no)
{
try {
var bl = new BusinessLayer();
bl.CheckOutItem(memberID, ISBN, copy_no);
}
catch (LibraryException ex)
{
var lfe = new LibraryFaultErrors();
lfe.Message = ex.Message;
lfe.LibraryErrorCode = ex.LibraryErrorCode;
throw new FaultException<LibraryFaultErrors>(lfe,
lfe.Message);
}
}