Our applications have now reached a point where we can begin to implement the presentation layers and user interaction logic. Parts 1-5 have focused on creating a database schema, stored procedure layer, database component classes, and business component classes. In this article, we'll implement John's ASPX GUI layer, which will tie all of our tiers together.
Web services B2B implementation demonstration
Welcome to the fourth article in a 10-part series exploring in detail the implementation of a B2B Web service. The series takes you through the development of a complete B2B Web services application. During the course of the series, we encourage Builder.com members to comment on the progress of the application. Do you have a better implementation? Do you have a question about our B2B solution? Start an article discussion and let us hear from you; we will do our best to address the issue.
Want to catch up on the series?
"Web services B2B implementation demonstration: Setting the scenario"
"Web services B2B implementation demonstration: Components, exception handling, and logging"
"Web services B2B implementation demonstration: Database design"
"Web services B2B implementation demonstration: John's business logic"
"Web services B2B implementation demonstration: Tom's app"
It's been my experience that the presentation tier is by far the most chaotic and difficult tier of code to manage. It's the vortex where the highly organized and object-oriented business and database tiers collide with the disarray of presentation logic and data transport.
Fortunately, the .NET framework has made significant advances to allow a more unified and cohesive presentation tier by applying OO principles to nearly every HTML element available. Coupling this with user definable GUI components, stylesheets, and other efficiencies creates a much more organized presentation tier than the previous methods of ADO Recordset iterations jumbled with inline ASP server code and HTML presentation code.
For John's application, we're going to take advantage of three simplistic, yet powerful, design patterns to help us organize the presentation tier: a custom user control, a stylesheet, and an ASPX identifier class. Let's begin with the stylesheet.
Open John's ASP.NET solution project and then open the default Styles.cssstylesheet file that was created by default with the solution. Replace the contents of this file with the code in Listing I.
Always begin a stylesheet by brainstorming a color scheme and setting up a style class for a variety of different HTML elements. You can then expand on these by creating variations of the style classes such as larger fonts, bolding, etc. The nice part about using a stylesheet is that you can change the entire look and feel of your application by modifying a single file. This will save you countless hours of page modifications if one day your customer decides that their buttons should be light blue instead of dark blue.
To create an ASPX identifier class, right-click the main ASP.NET project, and add a new class named WebPageNames.vb. Copy the code from Listing J into this new class.
In this class, we simply identify a set of public shared strings that map to the names of the ASPX pages in our project. This is a critical design aspect to the presentation tier. By removing hardcoded page name references from the ASPX tier, you can ensure that the navigation of your entire site will function as expected. Should a page name ever change, you simply need to modify it in one place, instead of sifting through your entire application updating page references.
Finally, we'll add a custom user control for page navigation. Navigation is critical to the usability aspect of an application. You can have the fanciest backend design ever created, but if your front-end usability is incomprehensible, it's all for naught.
Right-click the main WSB2BJohn application and Add | Add Web User Control. Name the control NavBar.ascx. Copy the HTML from Listing K into the HTML view of the control and the server side code from Listing L into the code behind file.
A custom user control is essentially like creating your own HTML element. It can be comprised of any conceivable combination of HTML and server code. The main concept is that the entire control is packaged into a reusable entity that you can then drag and drop onto other ASPX pages. In our case, we're simply creating a set of buttons for navigation that redirect to a particular ASPX page when clicked.
Stick to the requirements
Before beginning the implementation of your presentation tier, take a thorough review of the customer requirements. A detrimental side effect of building the actual visual presentation is that the customer begins to brainstorm all kinds of features and add-ons that were not part of the original requirements once they can actually see things in action. It's imperative that you stick to the original plan and push out additional features for a later release.
For John's application, we know we need to build the following features: view book inventory, edit a book, view/search orders placed from Tom's application, and complete orders. We'll add an additional landing or home page, which will give a summary overview when the application starts. Providing users with an overview starting page is a good idea for any application, because it lets the users know right away what they need to do as soon as they enter the application.
The ASPX pages
Now we're ready to begin adding our ASPX pages to the application. Let's first add all of the pages and get the code pasted into them, and then take a review of the important aspects of each page. Right-click the WSB2BJohn application, and select Add | Add Web Form for the pages outlined in the table below. For each page, copy the link from the HTML column into the HTML view for the page, and the code from the Code Behind column into the code behind class for the page.
Let's review the main aspects of the code for each page. Note that each page already has the NavBar control included. To place a custom control onto an ASPX page, you simply drag the control from the solution explorer onto the design view of any ASPX page. The code linkage is taken over for you behind the scenes.
This page simply presents a set of label controls with two pieces of information: the current date and the number of pending orders. When John enters his application, his immediate concern is what orders need to be confirmed for processing. By providing him this information, he knows exactly what he needs to do as soon as he enters the application.
The code behind file simply makes a call to our existing business component to retrieve all of the orders that have a status of Pending and places the number of rows in the resulting dataset into the presentation label control. The current date is placed into the date label control.
This page contains a datagrid for presenting a list of books and an edit button. You'll notice that we've implemented some custom logic to allow the datagrid to be clicked from any cell and have it select that row. This is accomplished by adding some logic to the ItemDataBound event, which is called for each row that is added to the datagrid.
The datagrid has a hidden button column that provides the select functionality. If this button was visible, you would notice a button on the leftmost column of the datagrid that allows the selection of a row in the grid. We make this button invisible and bind its functionality to the "onclick" event of every cell in the datagrid by using the Page.GetPostBackClientHyperlink method. This makes each cell in the datagrid behave as though it were a selection button control.
Finally, when an item is selected in the datagrid, we present an edit button, which, when clicked, extracts the ID of the book from the datagrid and redirects to the EditBook.aspx page. By putting the ID into a public property, our querystring remains uncluttered and allows the destination page to take care of performing the data lookup for the entity ID passed.
This page allows for the editing and saving of book data. When invoked, the page uses an advanced parameter passing method to retrieve the ID of the book. We know that this page is only called from ViewBooks.aspx; therefore, we cast the context handler as an instance of ViewBooks.aspx, which grants us access to the BookId property that was set when the Edit button was clicked on that page. Because the page is invoked using Server.Transfer(), we have access to the information of the invoking page during the lifecycle of the current request. Once the request ends, the data is lost.
We then make a business component call to retrieve the data for the BookId extracted from the context handler. Then, it's simply a matter of repopulating our presentation form with the data pulled from the database. The validation controls ensure that all required fields are filled before saving, and, if they are, another call is made through the business tier, which updates the database with the data from the form.
This page allows John to select a client, select an order status, and perform a search. When the page loads, it populates the client drop-down with the data from the database and manually populates the status drop-down with shared constants in the OrderDb class, which represent the set of valid statuses.
The datagrid used for presentation is flexible in that it allows for multiple contexts of functionality. When a search is performed for orders with any status other than Pending, a regular tabular display is presented. If the user searches for strictly Pending orders, a column is enabled which allows further functions to be performed.
The dynamic column is a pushbutton column that allows the user to confirm an order with the originating client via Web services. When this button is clicked, the details regarding the order are retrieved from the database and an asynchronous Web service invocation is performed. We want to perform the Web service call asynchronously so the user doesn't have to wait for a response. This is important in a Web application because, often, a user will repeatedly click a button if no response is received in a reasonable time frame.
In our case, the only client is Tom, so we invoke an instance of his Web service proxy class and make a call to the BeginConfirmOrder() method. We immediately return processing to the client and display a message to the user confirming invocation of the process. If the Web service successfully returns, the method CompleteOrder() is called when the asynchronous process returns to John's application. This method can safely assume that Tom's application has correctly processed the order, and John's application can now update the order as Complete.
Next in the series
In the seventh installment of Kevin Koch's Web services B2B implementation demonstration, he will implement all of the GUI screens required for Tom's use cases, set up the required GUI logic, such as validation controls, tie code behind files to business tier components, and demonstrate Data binding with Dataset objects.