Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

.NET Portfolio


Published on

  • Be the first to comment

  • Be the first to like this

.NET Portfolio

  1. 1. Matt Willmer’s .NET Portfolio Matt Willmer October 28, 2008
  2. 2. Summary This document contains a detailed explanation for the projects I worked on as part of the .NET Masters program at SetFocus from August 3, 2009 to October 28, 2009. A full curriculum description for this program can be found here: All of these projects were completed with .NET 3.5 using Visual Studio 2008, SQL Server 2008, IIS 6.0, and Windows Server 2003. Overall Requirements SetFocus required that I use a multi-tiered programming model for all of the projects that I’ve completed. This means that each assignment was divided into at least one Visual Studio project for each tier. The following is an example of the tiers that I used: Data Access Tier – A class library consisting of all of the code needed to interact with the database server. Generally, no other layer should contain any database interface code. Business Tier – A class library serving as a link to process and pass data between the Data Access and Presentation layers. Presentation Tier – A Windows Forms application or ASP.NET web application containing all of the code to display information to the user, and receive and validate user input. Entities Tier – A class library consisting of classes that define objects used to pass data. This tier is used by all other tiers. Typically the Data Access Tier will retrieve data from a database and use it to populate properties in objects defined in the Entities Tier. Those objects are passed through the Business Tier to the Presentation Tier to be consumed. When using LINQ to SQL, this tier is automatically generated by Visual Studio based on the database design, so it’s not always clearly separated from the Data Access Tier. Project 1 Overview The purpose of this project was to get familiar with coding in C#, especially with some of the features that make it unique from other languages like C++ or Java. This project was short and pretty simple--I was given a very detailed textual description of all of the needed classes and interfaces for a plausible business layer for a retail company. I put those specifications into code, and used a provided test dll to ensure that the classes functioned properly. The best way to see how these interact with each other would be to open the project in Visual Studio and use the Object Browser to look at their properties and methods. But since I didn’t design the class structure (I only coded it), I’ll select code snippets from the project to illustrate what I learned. C# Properties While instance variables (or fields) can be used to store data in a class in most programming languages, C# also provides a feature called Properties to enhance this. A public property can be accessed from
  3. 3. outside of a class in the same way that a field would be accessed, but with a property the programmer can specify code to run at the time the property is set or read through a set and get method. These come in handy when validating data or when the data comes from some internal structure that must be private. Additionally, the get and set methods for a public property can be set to private to make the property read-only or write-only. The following code snippet illustrates this: protected decimal unitPrice; public decimal UnitPrice{ get { return unitPrice; } set { if (value < 0.0m){ throw new ArgumentOutOfRangeException("UnitPrice", "UnitPrice cannot be less than 0."); } unitPrice = value; } } Code Snippet 1: AppTypesProduct.cs Lines 108 – 122 Working with System.Runtime.InteropServices.IEnumerator Enumerators allow a programmer to retrieve a series of values in a given order, one by one, often with a foreach loop. One way to produce an object of type IEnumerable is to inherit from it, and implement its methods to return values, and adjust the current value index. Another way is to use the yield return statement. The yield return statement defines the next value that will be returned by the iterator. This code snippet shows the yield return statement used to produce an IEnumerable that returns each of the properties stored in this class, one by one: public IEnumerable PropertyAndValuesCollection() { yield return String.Format("ID: {0}", ID); yield return String.Format("CompanyName: {0}", CompanyName); yield return String.Format("ContactName: {0}", ContactName); yield return String.Format("ContactTitle: {0}", ContactTitle); yield return String.Format("Address: {0}", Address); yield return String.Format("City: {0}", City); yield return String.Format("Region: {0}", Region); yield return String.Format("PostalCode: {0}", PostalCode); yield return String.Format("Country: {0}", Country); yield return String.Format("Phone: {0}", Phone); yield return String.Format("Fax: {0}", Fax); yield return String.Format("HomePage: {0}", HomePage); yield return String.Format("Type: {0}", Type); } //This allows a programmer to write foreach (string s in PropertyAndValuesCollection() { Console.WriteLine(s); } Code Snippet 2: AppTypesSupplier.cs Lines 127 - 142
  4. 4. Enumerators also come in handy when using LINQ, which I’ll talk about in Project 3. Comparing Objects Like C++, C# allows for operator overloading to perform math and Boolean operations on objects. The following code snippet shows the == operator overloaded: public static bool operator == (Supplier sup1, Supplier sup2){ if (object.ReferenceEquals(sup1, null) && object.ReferenceEquals(sup2, null)) { return true; } if (object.ReferenceEquals(sup1, null) || object.ReferenceEquals(sup2, null)) { return false; } return sup1.Equals(sup2); } Code Snippet 3: AppTypesSupplier.cs Lines 144 – 154 It’s important to note that some other.NET languages (Visual Basic, in particular) do not support operator overloading. Therefore, it’s always best to override the object.Equals() method as well. As you can see from the code snippet, the actual comparison of Supplier objects is being done by the Equals method (Which has been overridden, but not shown). It’s best to only implement the actual comparison code once in the Equals method. Also note that when checking for null input references object.ReferenceEquals() must be used so the operator function does not become recursive. The == method requires != to be overloaded as well (which isn’t shown in the snippet). Delegates and Events Events can be used to alert other objects that something has occurred without necessarily knowing what those objects are. They’re most common in programming user interfaces, although Visual Studio writes them automatically. There are some situations where a programmer may want to use his or her own event. First, a delegate must be declared: public delegate void CollectionModifiedHandler(object sender, ModificationEventArgs args); Code Snippet 4: AppTypesCollectionModifiedHandler.cs Line 8 An event was declared in the class that will broadcast the event, and the event was checked for a null value before calling it. An event will be set to a null value before any other classes have registered to receive it:
  5. 5. public event CollectionModifiedHandler CollectionModified; private void OnCollectionModified(ModificationEventArgs args){ if (CollectionModified != null) CollectionModified(this, args); } Code Snippet 5: AppTypesProducts.cs Lines 21 – 29 An object can register to receive the event like this: public void Register(Products pros) { pros.CollectionModified += new CollectionModifiedHandler(pros_CollectionModified); } public void pros_CollectionModified(object sender, ModificationEventArgs args) { lastEventDetails = "Modification Attempted " + args.ModificationEventStatus.ToString() + " " + args.ModifiedObjectReference.ToString(); } Code Snippet 6: AppTypesEventLogger.cs Lines 17 - 24 There are a lot of other small things I learned in this lab, like Attributes and Serialization. These are rather straightforward, so I won’t go into them in detail. Project 2 Overview The purpose of the second project was to gain a solid understanding of Windows Forms programming, and become familiar with as many controls from the Visual Studio Toolbox as possible. For this project, I wrote the Business and Presentation Layers for a plausible public lending library application. I was provided with a database structure, a script to populate the database with test data, and a dll containing code to actually interact with the database (The Data Access Layer). In the next project, I’ll be writing my own code to replace the dll’s code to connect to the database. (SetFocus choose to teach Windows Forms before ADO.NET) User Interface The Library system was required to perform four functions: add an adult member, add a child member, check out a book, and check in a book. Adult and Child members differ in the information that is collected about each type. Because only these four simple functions were needed, I chose to put a simple ListView on the main form, with the View property set to “LargeIcon.” The main form is shown below:
  6. 6. Figure 1: Main Form for the Library Application The following forms were created for the Add Adult and Add Child functions: Figure 2: Add Adult and Add Child Forms For this project, modal feedback was discouraged, that means that it was considered unacceptable to alert the user of an error with a MessageBox that required them to click OK to continue. An error provider control was added to all forms to provider user feedback. A method was registered to be called for each textbox when that textbox’s Validating event occurred (when the user moves focus away from it). Those methods validated the data in the textbox using a function in the Business Layer, and used the error provider to give the user an explanation of the error. An error provider displays a red icon near the fields in error, and provides an explanation in the tooltip that the user sees when hovering over it, as shown below: Figure 3: The Error Provider at work in the Add Adult Form The project required checking out a book to be a three step process:
  7. 7. 1. The Librarian enters the patron’s card number, confirms the name and address, and may view the books already checked out by the patron. 2. If the Patron’s card is not expired, and he or she has less than four books checked out, the system allows the librarian to enter identifying info for the book (ISBN and copy number). The librarian confirms the book’s title and author. 3. If the book is not checked out, the librarian may check it out to the patron. If the book is marked as checked out (which the project requirements state happens often when a book is returned and re-shelved without being checked in), the librarian has the opportunity to automatically have it checked in and then checked out to the patron. The following shows the book checkout form in each of the three stages of the process:
  8. 8. Figure 4: Three Stages of the Checkout Process Similarly, checking in a book was a two stage process: the librarian enters the books identifying info (ISBN and copy number), the system confirms the title and author of the book, and shows who the book is checked out to. The librarian can then choose to check the book in or cancel. This process is illustrated below: Figure 5: Check in process Project 3 Overview The purpose of project 3 was gain a solid understanding of database interactivity by using LINQ to SQL. In Project 2, I was given compiled dlls to define the Data Access and Entities tiers for the library project. In this project, I wrote code to produce my own dlls to replace those. Although I was required to use LINQ to SQL in this project, I was also taught the traditional ADO.NET way of sending actual SQL statements to the database server using connection, command and data reader objects. In fact,
  9. 9. SetFocus spent just as much class time teaching ADO.NET and Microsoft transact-SQL as they did with LINQ. I understand that there are arguments for and against using LINQ. Many programmers feel LINQ produces inefficient SQL queries that can impair performance. While SetFocus acknowledges this, they have encouraged me and my classmates to use it because Microsoft claims great improvements will be made to LINQ in Visual Studio 2010. Having prior experience writing SQL queries by hand, I’m willing to take the time to use ADO.NET to manually submit queries to the database server. But I’m also eager to see what changes are in store for LINQ in Visual Studio 2010. The Database Structure I was given a database structure to use for this project. This same database structure was used in Project 2. The following diagram illustrates the most important tables: Figure 6: Part of database structure. (More tables were used, but these are the most relevant to the following examples.) Each work written by an author has an entry in the title table. Each ISBN has an entry in the item table. (So a written work might be published under multiple ISBNs, one for each translation, or cover type.) For each ISBN one or more copies may exist in the library. A copy represents a physical book that a patron may check out. Each member in the library has one row in the member table, and one row in either the juvenile or adult tables. Because a juvenile’s address information is required to be the same
  10. 10. as the juvenile’s parent, the juvenile table contains a pointer to the juvenile’s parent so the data is not duplicated. The following query was written to select all of the members and their information: SELECT member.member_no, firstname, middleinitial, lastname, street, city, state, zip, phone_no, expr_date, NULL AS adult_member, NULL AS birth_date, 'ADULT' AS Type FROM adult INNER JOIN member ON adult.member_no = member.member_no UNION SELECT juvenile.member_no, firstname, middleinitial, lastname, street, city, state, zip, phone_no, expr_date, adult.member_no AS adult_member, birth_date, 'JUVENILE' AS Type FROM juvenile INNER JOIN member ON juvenile.member_no = member.member_no INNER JOIN adult ON juvenile.adult_member_no = adult.member_no Code Snippet 7: Query to retrieve all members Similarly, a query was written to select all of the items (books). These queries were put into views on the database server, and the following entities diagram was created based on those views in Visual Studio: Figure 7: Entities Diagram
  11. 11. This diagram shows that Visual Studio will automatically create Item, Member, JuvenileMember, and AdultMember classes and will automatically store data from the database in those classes when performing a query on the DataContext. JuvenileMember and AdultMember inherit from Member, and the properties have been set such that either a JuvenileMember or AdultMember object will be created for each row depending on the value in the Type column. Four procedures were created on the database server, AddAdult, AddJuvenile, CheckOutItem, and CheckInItem. Those procedures were added to the Entities Diagram (Visual Studio does not show this graphically). A class was created in the Data Access Layer to provide methods for the Business Layer to call to interact with the database. This function is an example from that class that uses a LINQ query: public Member GetMember(int isbn, short copyNumber) { Member result; try { LibraryEntitiesDataContext ledc = new LibraryEntitiesDataContext(); var query = (from m in ledc.Members join i in ledc.Items on m.MemberID equals i.MemberNumber where i.ISBN == isbn && i.CopyNumber == copyNumber select m).Single(); result = (Member)query; } catch (Exception ex) { throw new LibraryException(ErrorCode.NoSuchMember, ex.Message, ex); } return result; } Code Snippet 8: LibraryDataAccess.cs Lines 121-142 This function could’ve been written using ADO.NET like this:
  12. 12. public Member GetMember(short memberNumber, string connectionString){ Member result; SqlConnection conn = new SqlConnection(connectionString); conn.Open(); SqlCommand command = conn.CreateCommand(); command.CommandText = "SELECT * FROM Member_View WHERE member_no = " + memberNumber.ToString(); SqlDataReader reader = command.ExecuteReader(); if (reader.Read()){ if (reader.GetString(12) == "ADULT"){ result = new AdultMember((short)reader.GetValue(0), reader.GetString(1), reader.GetString(2), reader.GetString(3), reader.GetString(4), reader.GetString(5), reader.GetString(6), reader.GetString(7), reader.GetString(8), (DateTime)reader.GetValue(9)); } else{ result = new JuvenileMember((short)reader.GetValue(0), reader.GetString(1), reader.GetString(2), reader.GetString(3), reader.GetString(4), reader.GetString(5), reader.GetString(6), reader.GetString(7), reader.GetString(8), (DateTime)reader.GetValue(9), (short)reader.GetValue(10), (DateTime)reader.GetValue(11)); } } reader.Close(); conn.Close(); return result; } Code Snippet 9: Returning a Member using ADO.NET Project 4 Overview The purpose of this project was to master ASP.NET and gain some familiarity with Microsoft IIS. In this final stage of the library project, I created a web based presentation layer. A Note on Cross-Browser Compatibility I feel the issue of cross-browser compatibility is of such importance that every web programmer should be aware of it even if he or she is not responsible for the web design. A web site that functions properly, but displays incorrectly can turn away users just easily as one that doesn’t function at all. Different web browsers and even different versions of the same web browser may display a page differently. The ASP.NET server controls render correctly in virtually every browser. A programmer who works mostly with ASP.NET controls and rarely writes any HTML by hand may not even be aware of cross browser display issues. Users have formed strong bonds with their favorite web browser, so asking them to use a particular browser is usually unacceptable. Currently, statistics show that Internet Explorer and Firefox are the most popular browsers representing nearly 90% of all internet users. Although as many
  13. 13. browsers as possible should be tested, a page that displays correctly in these two browsers will typically display correctly in most other browsers. Setting Up the Master Page The following illustration shows the master page that I created for this site: Figure 8: MainMaster.master The following code snippet shows the relevant CSS for the master page:
  14. 14. body .centerColumn { { font-family: Sans-Serif; margin-left: auto; background-color: margin-right: auto; #669900; margin-top: 0px; margin: 0px; width: 950px; padding: 0px; } } .leftCenterColumn .header { { background-color: margin: 0px; #FFFFFF; margin-bottom: 10px; width: auto; padding: 0px; margin-top: 10px; width: 100%; margin-right: 10px; background-color: border: 1px solid #000005; #000000; color: #FFFFFF; } } .leftCenterColumnContent .headerContent { { margin-top: 15px; margin-right: auto; margin-bottom: 15px; margin-left: auto; } width: 950px; .rightCenterColumnContent } { .patronsServed margin: 15px; { } font-style: italic; .rightCenterColumn margin-left: 25px; { background-color: } #FFFFFF; .mainTitle width: auto; { margin-top: 10px; margin-left: 10%; margin-left: 10px; font-size: x-large; border: 1px solid } #000000; } Code Snippet 10: CSS classes for the master page As you can see, I applied a style to the body, setting the background color to green and the font to whatever sans-serif font the browser chooses. I set the margin and padding to 0 to ensure that elements can reach up to the edges of the page in all browsers. The header class is used to define the black (actually very dark blue) stripe across the top of the page. The left column contains a TreeView control with the data source set to a SiteMapDataSource, which loads the data from a sitemap file. This allows the links in the site map to all be specified in one XML file. centerColumn defines the main content area in the middle of the page below the dark stripe. I chose to set this to a fixed 950 pixels. Generally this is the only thing I would set to a fixed pixel value. The left and right columns inside of the center column are set to widths of 20% and 80% respectively (which is a percent of the center column, not the entire page). The center column could be set to say 90% of the page instead of 950 pixels. But this may cause problems. For example, the left column takes up 20% of the center area or about 190
  15. 15. pixels. The text inside of the column fills it well. If the center column were set to a percent, its width could easily approach 2,000 pixels on a high resolution wide screen monitor. This could cause the left column to almost double in width, but the font would likely stay the same size. The font would appear to take only a small part of the left column. Although this would utilize all of the available space on the page, it would look awkward. Setting the width of the center column to a fixed width will cause wasted space on a high resolution display, but it will ensure a uniform look for all users. Up until now, the most common display resolution for internet users was 768 x 1024. Although display resolutions are constantly getting higher, planning for this resolution seems to produce the best results. Typical Page Layout The center of the master page contains a content place holder that will contain the main part of the page. The following illustration shows the check out page: Figure 9: Library Check out page On this page, Label controls were used to display the library patron’s personal information. The Enter and Select Book buttons cause a postback of the page, and the Visible property of the appropriate labels as well as the entire Book Information fieldset is set to true or false as needed. Setting the Visible property of an ASP.NET server control to false prevents it from being rendered. (This should not be confused with setting the style property to “visibility: none;”, in which case, the HTML for the control is
  16. 16. still rendered, but the browser will not display it.) The checked out books are displayed by a GridView control which is bound to an ObjectDataSource control. While the ObjectDataSource control could’ve been bound to the same ItemsDataSet that was used in the Windows Forms project, additional columns were desired in this project. In order to not break the functionality in the Windows Forms project, a new DataSet was created in the Entities Layer. Upon binding the dataset, each value in the Due Date column is checked and the style property of that cell is changed if the book is overdue. A script manager was added to the page and most of the page was put inside of an UpdatePanel control. The UpdatePanel causes ASP.NET to automatically generate Javascript to submit AJAX request to the server such that the entire page will not reload when a control that would cause a postback is triggered. This provides a faster response for the users, and causes a small reduction in bandwidth use. The Modal Dialog This project required that a Librarian be able to check out a book by entering the patron’s card number. I felt it would also be convenient for a Librarian to look up the patron’s card number by entering his or her name. A ModalDialog was created which appears when a user clicks the “Lookup” LinkButton and requires the user to take action within the dialog before being able to interact with the rest of the page - - just like a MessageBox. The following ModalDialog was created: Figure 10: The ModalDialog on the check out page
  17. 17. The Dialog box in the center of the page was initially created as a Panel control at the bottom of the existing page. The functionality shown above was created by simply adding a ModalPopupExtender control to the page from the AJAX control toolkit. The properties of the ModalPopupExtender were set to indicate which Panel control to use, which CSS classes to use for the dialog, as well as making the outside of the dialog opaque, and to indicate which buttons on the panel are to be used for accept and cancel. The style property of the Panel was set to “display: none;” so that the Panel’s HTML would be rendered, but not displayed by the browser until the ModalPopupExtender’s Javascript changed it. Within the Panel, AJAX requests were used to update the search results in the ListBox. Every time a key is pressed in the first or last name TextBoxes, the name is sent to the server, and the server returns a list of name/card number pairs to display in the list box. This allows the user to find a member even if he or she only partially knows how to spell the name. The following Javascript submits the name to the server: function updateResults() { var firstName = document.getElementById(searchFirstNameTextBox).value; var lastName = document.getElementById(searchLastNameTextBox).value; var name = firstName + "~" + lastName; PageMethods.GetSearchResults(name, OnSucceeded, OnFailed); } Code Snippet 11: JavaScript function to submit names Note that the actual ID of the text boxes is retrieved from variables. It is not possible to predict the ID that will be used in the HTML that ASP.NET renders for the server controls. Therefore, it is necessary for the server to generate Javascript which stores the names of the needed controls in variables for use by the browser at runtime. The following code is contained in the server-side page markup to produce this code: <script type="text/javascript" language="javascript"> var cardNumberTextBox = '<%=cardNumberTextBox.ClientID%>'; var searchFirstNameTextBox = '<%=searchFirstNameTextBox.ClientID%>'; var searchLastNameTextBox = '<%=searchLastNameTextBox.ClientID%>'; var enterButton = '<%=enterButton.ClientID%>'; </script> Code Snippet 12: Javascript to store the control IDs in variables When the updateResults function calls the GetSearchResults function, the ScriptManager submits an AJAX request to the server. In order to enable this functionality, the ScriptManager’s EnablePageMethods property must be set to true, and the method being called must be public and static, and contain the [WebMethod] attribute which requires the System.Web.Services namespace. The following web method was created:
  18. 18. [WebMethod] public static string GetSearchResults(string name){ string firstName = name.Substring(0, name.IndexOf("~")); string lastName = name.Substring(name.IndexOf("~") + 1); SearchMemberDataSet sm = DataManipulator.FindMember(firstName, lastName); string output = ""; foreach (DataRow row in sm.Tables[0].Rows){ if (output == ""){ output += row[0].ToString() + "~" + row[1].ToString(); } else{ output += "~" + row[0].ToString() + "~" + row[1].ToString(); } } return output; } Code Snippet 13: Server-Side web method to return possible patrons This method calls into the Business layer, which uses the Data Access layer to retrieve possible users. The actual logic to choose users is contained in a new database procedure. Upon selecting a name and clicking select, the corresponding card number will be inserted into the card number TextBox, the modal dialog will disappear, and the Enter Button will be triggered. Validation Although ASP.NET offers very versatile validation controls, like the RangeValidator or RegularExpressionValidator, the best choice for this project was the CustomValidator because the actual validation logic was already written in the Business layer earlier. The main drawback to using the CustomValidator is that it cannot automatically generate Javascript for client-side validation—so the validation logic would need to be rewritten in Javascript. However, client-side validation was not needed for this project, so this was not done. The following illustration shows how the validation controls will appear to the user:
  19. 19. Figure 11: The validation controls Each of the CustomValidators calls a validation function in the business layer to check the input. It sets the IsValid property of the event arguments to true or false. If the input is invalid, it then sets the validator’s error message to the value returned by the business layer. protected void firstNameCustomValidator_ServerValidate(object source, ServerValidateEventArgs args){ string error = MW.LibraryBusiness.Validate.ValidateName(args.Value); if (error != ""){ error = "First Name " + error; } firstNameCustomValidator.ErrorMessage = error; args.IsValid = (error == ""); } Code Snippet 14: A validation event handler
  20. 20. Project 5 The purpose of project 5 was to gain an understanding of the Windows Communication Foundation. WCF allows for the creation of service projects. A service project can then be hosted in a Windows Service or it can be hosted on a web server running IIS. Remember that in my Library project there is a clear separation between presentation code and the logic / database interaction code. The goal of this project was to expose the business layer code to an outside party by creating a service project that calls into the business layer and emits the results through the service. The service was then hosted in IIS, and the existing ASP.NET presentation layer was modified to retrieve data from the service hosted on IIS rather than from the business directly. A service must have a defined ServiceContract that contains DataContracts and OperationContracts to define how the service will work. These are defined by creating an interface with abstract methods and applying the appropriate attributes as shown below: [ServiceContract] public interface ILibraryService { [FaultContract(typeof(LibraryFault))] [OperationContract] Member GetMember(short id); Code Snippet 15: ServiceContract definition Note that OperationContracts were defined for all methods in the Business Layer (not shown above). Because a service runs in a process by itself, it cannot throw exceptions to the consuming process. When an uncaught exception occurs in a service, a fault message is generated and sent to the consuming process. Every method that throws a fault exception must have a FaultContract attribute as shown above. The following class defined a custom FaultContract that was used to preserve the error code from any LibraryExceptions that were thrown: [DataContract] public class LibraryFault{ [DataMember] public string ErrorCode; [DataMember] public string Message; [DataMember] public string OtherID; } Code Snippet 16: The custom LibraryFault The following class was defined to implement the ILibraryService interface:
  21. 21. [ServiceBehavior(IncludeExceptionDetailInFaults = true)] public class LibraryService : ILibraryService{ [PrincipalPermission(SecurityAction.Demand, Role = "LibraryPartner")] public MW.LibraryEntities.Member GetMember(short id){ MW.LibraryEntities.Member result = null; try{ result = DataManipulator.GetMember(id); } catch (LibraryException le){ var fault = new LibraryFault(); fault.ErrorCode = le.LibraryErrorCode.ToString(); fault.Message = le.Message; fault.OtherID = le.OtherMemberID.ToString(); throw new FaultException<LibraryFault>(fault); } catch (Exception e){ var fault = new LibraryFault(); fault.ErrorCode = ErrorCode.GenericException.ToString(); fault.Message = e.Message; fault.OtherID = "-1"; throw new FaultException<LibraryFault>(fault); } return result; } Code Snippet 17: LibraryService implementation As you can see, the implementation of the GetMember method calls into the business layer, catches any exceptions that are thrown, and re-throws them as FaultExceptions. The service was hosted in IIS, and a service reference was added to the ASP.NET website so that it can call into it by creating a LibraryServiceClient object. The following code from the MainMaster.master.cs file shows a label being populated with the total number of users in the Library: LibraryServiceClient proxy = new LibraryServiceClient(); patronsServed.Text = string.Format("{0:0,0} " + patronsServed.Text, proxy.GetTotalMembers()); proxy.Close(); Snippet 18: Using the LibraryServiceClient