- Understanding Page Events
- Understanding Page Properties
- Understanding Directives
- Code Separation and Using Code-Behind
- Summary
Understanding Page Properties
As I've said over and over and over and over again, ASP.NET is an object-oriented programming paradigm, and ASP.NET pages are no exception. They are objects, as well, and have properties and methods just like every other object.
Let's take some time to explore some of the key properties that the ASP.NET page object has. First, it is helpful to know where in the .NET Framework the Page object is. It is located in System.Web.UI. You can go there in the class browser that I mentioned in earlier chapters (http://www.gotdotnet.com) and investigate all the properties. In this book, however, we are going to cover the biggies, the heavyweights, the granddaddies. In other words, we're going to cover the ones that are used most commonly.
The Page object properties covered in this section are:
Application
IsPostBack
Request
Response
There are actually a few additional properties, such as Session and Validation, that are covered in other chapters and are pointed out as Page object properties then.
NOTE
If you come from a traditional ASP programming background, many of these probably look familiar to you. In traditional ASP, many of these ASP.NET Page properties were what made up the default objects in the language. You ask, "Why are they now properties of the page instead of remaining objects?" In reality they are still objects and can be found in the System.Web section of the .NET Framework. To simplify the use of objects, many properties of objects are really just instances of other objects. You will see this throughout the framework. Actually, just about every property is an instance of another object. For instance, any property that is a string is actually an instance of the System.String object. So properties in the .NET Framework are generally just instances of other objects.
Application
The Application property or HttpApplicationState object contains a collection of data that is available across the entire application during the life of the application. It is a shared variable among the users and is an easy-to-use place to store global information that will be needed across your application.
Setting an Application variable is a piece of cake:
Visual Basic .NET
Application("Publisher") = "New Riders" OurLabel.Text = Application("Publisher")
C#
Application("Publisher") = "New Riders"; OurLabel.Text = Application("Publisher");
This would write the words "New Riders" to your browsers. You typically wouldn't go around setting an application variable all over the place every time a page loaded. Because it is an application-level variable, under most circumstances it really needs to be set only once during the life of an application. ASP.NET provides a way to set Application variables (in addition to many other things) within a file called the global.asax, which resides in the root folder of your application. On a web site, this is typically the folder that your domain points to, where your index or default home page is located. This example creates four application variables in the Application_OnStart event, which happens the first time a web page is requested from an application. This doesn't mean that web service on the server must be stopped and started if you make a change to anything in the Application_OnStart. ASP.NET is smart enough to recognize the change and reset the variable's value.
Visual Basic .NETglobal.asax
<script language="vb" runat=server> Sub Application_OnStart() Application("Publisher") = "New Riders" Application("BookTitle") = "ASP.NET for Web Designers" Application("Author") = "Peter" Application("Rating") = "5 Stars, WHAHOOO!!" End Sub </script>
C#global.asax
<script language="c#" runat=server> void Application_OnStart(){ Application["Publisher"] = "New Riders"; Application["BookTitle"] = "ASP.NET for Web Designers"; Application["Author"] = "Peter"; Application["Rating"] = "5 Stars, WHAHOOO!!"; } </script>
Now, if you make a file that requests the application variables, you can see how they are retrieved.
Visual Basic .NETpage_application_vb.aspx
<%@ page language="vb" runat="server"%> <script runat=server> Sub Page_Load() Title.Text = "<u>Title:</u> " + Application("BookTitle") Publisher.Text = "<u>Publisher:</u> " + Application("Publisher") Author.Text = "<u>Author:</u> " + Application("Author") BookRating.Text = "<u>Rating:</u> " + Application("Rating") End Sub </script> <html> <title>Application</title> <body> <asp:label id="Title" runat="server"/><br> <asp:label id="Publisher" runat="server"/><br> <asp:label id="Author" runat="server"/><br> <asp:label id="BookRating" runat="server"/> </body> </html>
C#page_application_cs.aspx
<%@ page language="cs" runat="server"%> <script runat=server> void Page_Load(){ Title.Text = "<u>Title:</u> " + Application["BookTitle"]; Publisher.Text = "<u>Publisher:</u> " + Application["Publisher"]; Author.Text = "<u>Author:</u> " + Application["Author"]; BookRating.Text = "<u>Rating:</u> " + Application["Rating"]; } </script> <html> <title>Application</title> <body> <asp:label id="Title" runat="server"/><br> <asp:label id="Publisher" runat="server"/><br> <asp:label id="Author" runat="server"/><br> <asp:label id="BookRating" runat="server"/> </body> </html>
As you can see in Figure 4.5, the page requested these application variables and displayed them in the browser just as expected.
Figure 4.5 Application variables are a simple way to make routine and application- wide information available to you.
TIP
As I mentioned in Chapter 1, there is another file that can contain not only application variables but a ton of other information: the web.config file. This is an XML document that allows you to configure many elements of your web application and isn't limited to one file per application. You can add a web.config file to every folder in your application to set its configuration, rules, or variables. This file is a bit out of the scope of this book, but if you are looking for greater control over your application, the web.config file may be your answer. In addition, there are great performance advantages in using variables from within the web.config file over an application variable. You can learn more about configuring your web applications with the web.config file in the .NET Framework SDK at the following link:
ms-help://MS.NETFrameworkSDK/cpguidenf/html/cpconaspnetconfiguration.htm
IsPostBack
You saw the IsPostBack property mentioned in one of the earlier examples. This is an incredibly useful property that you will find yourself using all the time when you are processing forms.
As a matter of fact, this property is at the core of some of the most powerful features in ASP.NET and its pages. ASP.NET web forms are built on the concept of making round trips to the server. It's a simple property whose value is either true or false. The property is set to true whenever you post a page to the server with a runat="server" directive in the form tag. Form tags with runat="server" directives always post back to themselves. If you put an action property in the tag, it will basically be ignored.
This property is basically used, as I've said, to determine whether a page is being loaded for the first time or is being posted back to itself. Take a look:
Visual Basic .NETpage_postback_vb.aspx
<%@ page language="vb" runat="server"%> <script runat=server> Sub Page_Load() OurTitle.Text = "No this page wasn't posted back" If IsPostBack then OurTitle.Text = "Yes this page has been posted back" End If End Sub </script> <html> <title>Was this page posted back?</title> <body> <form runat="server"> <asp:label id="OurTitle" runat="server"/><br><br> <asp:Button id="PostBack" text="Post this Form?" runat="server"/> </form> </body> </html>
C#page_postback_cs.aspx
<%@ page language="cs" runat="server"%> <script runat=server> void Page_Load(){ OurTitle.Text = "No this page wasn't posted back"; if (IsPostBack){ OurTitle.Text = "Yes this page has been posted back"; } } </script> <html> <title>Was this page posted back?</title> <body> <form runat="server"> <asp:label id="OurTitle" runat="server"/><br><br> <asp:Button id="PostBack" text="Post this Form?" runat="server"/> </form> </body> </html>
You can see in Figure 4.6 that the first time you request this page, you are presented with the default message because the IsPostBack property is false on the initial load of that page, so the if branching statement doesn't execute its code.
Now what happens if you click the button and post the form? In Figure 4.7 you can see that after you post the form, the label's text value is changed because IsPostBack is now true and the if block executes.
This technique will be used and demonstrated in abundance in later chapters, where you will be able to see it under many different circumstances. So hold your horses and don't get your undies in a twist.
Request and Response
I've always told people who ask me about the Internet that it's not a big mystical thing that can't be understood or pinned down. It's really very simple. It's a communication tool, just like a phone or even more simply a piece of paper and a pen. It's a way to say something to others and, thankfully, as dynamic languages have become so prolific, they can say stuff back and we can respond to what they said programmatically.
Picture two grandmothers sitting at a kitchen table enjoying a cup of tea and good conversation. The air is filled with the pleasing aroma of fresh baked apple pie so thick you can almost taste it.
Ethel: "Bernice, do you want to see my latest masterpiece? It's a deep dish apple pie done to perfection."
Bernice: "Certainly Ethel. Let me have a look see."
Ethel gets up from the table and saunters over to the window sill where the golden brown pie sits. She carefully slides it off the sill onto her toweled hand and returns with the same grace to the table. She approaches Bernice and lowers it in front of her so the waves of succulent aroma waft up to her nose.
Bernice: "Um Um!!!!! Can I have a piece of that?"
Ethel: "You sure can."
Ethel cuts and serves a slice of that delicious pie to Bernice, who proceeds to ravage it mercilessly. Whipped cream, crust, and apples fly as Bernice devours her prize. In between forkfuls, Bernice lifts her apple pie covered face and says:
Bernice: "Can I have the recipe? This is delicious!"
Ethel, also now covered in the remains of a once beautiful piece of apple pie from Bernice's frenzy, pulls the recipe from her recipe file and gives it to her dear friend...Bernice.
The End
Okay, a little too dramatic for you? I'm sorry. Sometimes I get carried away. I have behaved quite professionally so far this chapter, and I though it was time to get silly again.
Anyway, the point of my dramatic depiction of Ethel and Bernice was to demonstrate communication and to give an example that shows a bunch of different types of requests and responses. Later we will try to programmatically reproduce this scene and help you see it in action. First, though, it's a good idea to look a bit more into the Request and Response properties of your ASP.NET pages.
Request
If you can think of the Request as a question mark, you will quickly and easily understand what it does in concept. It's similar to Bernice asking whether she can have a piece of pie or have a copy of the recipe. It's also good for finding out what the response was to a question we ask just like Ethel asked whether Bernice wanted to see the pie. We find out the condition of things being sent to the server with the Request.
As I said with the Application property, the Request and Response properties are both actually objects in their own right and can be explored in the class browser I redundantly mention.
You can get tons of data by using the Request object, and I covered a few of them here. There are a handful that you will find yourself using over and oversuch as Request.Form, Request.Querystring, and othersand that you will find yourself using as a very pointed tools for specific tasks. You won't use all the properties of the Request all the time, but they are powerful nonetheless.
For instance, let's take the Request.IsSecureConnection property. This is a nifty little tool that checks to see whether you are communicating via an HTTPS secure protocol or not. It returns a Boolean value of true or false, depending on whether the connection is secure. It's a neat gadget that will definitely come in handy in certain situations, but it's not something you're gonna use every day. Table 4.1 provides a list of some that you will use just about every day.
Table 4.1 Request Object Properties
Request Property |
Description |
Browser |
An instance of the HTTPBrowserCapabilites object that is chock full of information about the client's browser and its capabilities. |
Cookies |
Enables you to store information on the client's machine and retrieve it at a later time. |
Form |
Retrieve the values of form elements submitted during a form post. |
QueryString |
Retrieve the values of name/value pairs stored in the requesting URL. These can be inserted directly or can be the result of a form being submitted via the Get method. |
ServerVariables |
An ocean full of variables about the request. |
Now take a look at a few of these in action. The following is a code example that incorporates a few of these Request properties.
Visual Basic .NETpage_request_vb.aspx
<%@ page language="vb" runat="server"%> <script runat=server> Sub Page_Load() OurLabel.Text = "Here are some of our Request properties in action<br>" OurLabel.Text += "My Browser is: " + Request.Browser.Browser + "<br>" OurLabel.Text += "Our Querystring Color is: " +
Request.QueryString("color") + "<br>" OurLabel.Text += "This file is located at: " +
Request.ServerVariables("Path_Translated") + "<br>" End Sub </script> <html> <head> <title>Page Request</title> </head> <body> <asp:label id="OurLabel" runat="server"/> </body> </html>
C#page_request_cs.aspx
<%@ page language="c#" runat="server"%> <script runat=server> void Page_Load(){ OurLabel.Text = "Here are some of our Request properties in action<br>"; OurLabel.Text += "My Browser is: " + Request.Browser.Browser + "<br>"; OurLabel.Text += "Our Querystring Color is: " +
Request.QueryString["color"] + "<br>"; OurLabel.Text += "This file is located at: " +
Request.ServerVariables["Path_Translated"] + "<br>"; } </script> <html> <head> <title>Page Request</title> </head> <body> <asp:label id="OurLabel" runat="server"/> </body> </html>
NOTE
Please note that whenever you are specifying an item in a collection, such as the Request.Form or Request.Querystring, the bracket types around the item are different in the two languages. In Visual Basic .NET, you use parentheses and quotes around the item name, whereas in C# you use square brackets and quotes. If you come from a traditional ASP/VBScript background and decide to use C# as your language, you will need to watch out for this.
If you look at Figure 4.8, you can see we are requesting the value of the browser being used to view the ASP.NET page, a value in the QueryStringor in other words, name/value pairs passed in the URL of the pageand a ServerVariable called "Path_Translated".
Figure 4.8 The HTTPRequest object enables you to retrieve data either passed to a page or submitted by the user.
There are times when data that you request is a property like the Request .Browser.Browser property. This may look redundant with Browser.Browser being in the Request, but remember that you are dealing with an addressing system here, or a namespace. The first "Browser" is a property of the page and is an instance of the HTTPBrowserProperties object. That object has a property called Browser, and hence the Browser.Browser in the Request. It might have made more sense if I had written Request.Browser.JavaScript, which would have returned a Boolean true or false depending on whether a browser is JavaScript-enabled.
The second request type that you will see is called a collection and requires you to identify what you're looking for. With the QueryString, I knew I was looking for "color" and requested that from the QueryString collection. The Request.Form collection operates the same way. The contents of the Form and QueryString generally are determined by the programmers of the website, and you can pass whatever name/value pairs you would like through these methods.
With the ServerVariables, you need to specify the variable that you are requesting, but these aren't programmer-defined. The available variables are determined in ASP.NET and are a bit too numerous to list and describe in detail in this book. I would recommend that you investigate the .NET Framework SDK for more information on ServerVariables.
Now that you've seen how to get information from the user and how to request all types of different data, you need to be able to respond to those requests. ASP.NET has very generously provided an instance of the HTTPResponse object as a page property called Response.
Response
Every time that Bernice or Ethel asked a question or made a request, the other had a response. When Ethel asked:
"Bernice, do you want to see my latest masterpiece? It's a deep dish apple pie done to perfection."
Bernice had a response:
"Certainly Ethel. Let me have a look see."
There was a conversation. This is what the Request and its counterpart the Response allow us to do: carry on a conversation with the visitors of the web sites we create.
Table 4.2 lists a few of the common Response object's properties and methods.
Table 4.2 Response Object Properties and Methods
Response |
Description |
Buffer |
This controls the flow of data from the server to the user's browser. When the buffer is set to true, which it is by default, data isn't sent to the browser until the server completely processes the page. When the buffer is set to false, data is sent to the browser as soon as it's processed and doesn't wait for the entire page to process. |
Clear() |
Use this when the buffer is set to true and you want to get rid of everything processed up to where the Clear() is. |
End() |
Use this when the buffer is set to true and you want to send to the browser what you've processed up to the point where the End() is and stop processing the page at that point. |
Flush() |
Use this when the buffer is set to true and you want to send to the browser what you've processed up to the point where the Clear() is. |
Redirect() |
Allows you to send the user to a new URL. |
Write() |
Allows you to write information into ASP.NET pages. |
WriteFile() |
Writes the specified file directly to an ASP.NET page. |
I have this really great news; do you want to hear it? Nah. I'm not gonna tell you 'til I know everything. I want to wait 'til I know the whole story first before I let you know. Well...maybe I'll tell you what I know so far.
UGGHHHHHH!!! It's all over!! I don't want to talk about it anymore. I can't go on. I can't even face it anymore. I'm ruined...I'm ruined ......I'm ruined.
Dramatic, huh? In a feeble and yet to be determined successful manner I was trying to parallel how the Buffer and some of its methods would work in a practical application. If you want to hold back information from being delivered, you set the page's Buffer property to True. Then you can manipulate the page however you want as you progress. Look at an example of the HttpResponse object in action. You are using an object in the System.Threading namespace to pause the pages processing using a method called Sleep. You will hardly ever have need for this, but it helps me to demonstrate some of the Buffer features of the HttpResponse object.
Visual Basic .NET
<%@ page language="vb" runat="server" buffer="true"%> <%@ import namespace="System.Threading"%> <html> <head> <title>Hi</title> </head> <body> <% Response.Write(DateTime.Now + " The First Response.Write() has executed.<BR>" ) Response.Flush() Thread.Sleep(5000) Response.Write(DateTime.Now + " The Second Response.Write() has executed.<BR>" ) Response.Flush() Thread.Sleep(5000) Response.Write(DateTime.Now + " The Third Response.Write() has executed.<BR>" ) Response.Clear() Thread.Sleep(5000) Response.Write(DateTime.Now + " The Fourth Response.Write() has executed.<BR>" ) Response.End() Response.Write("Where does this text go?") %> </body> </html>
C#
<%@ page language="c#" runat="server" buffer="true"%> <%@ import namespace="System.Threading"%> <html> <head> <title>Hi</title> </head> <body> <% Response.Write(DateTime.Now + " The First Response.Write() has executed.<BR>" ); Response.Flush(); Thread.Sleep(5000); Response.Write(DateTime.Now + " The Second Response.Write() has executed.<BR>" ); Response.Flush(); Thread.Sleep(5000); Response.Write(DateTime.Now + " The Third Response.Write() has executed.<BR>" ); Response.Clear(); Thread.Sleep(5000); Response.Write(DateTime.Now + " The Fourth Response.Write() has executed.<BR>" ); Response.End(); Response.Write("Where does this text go?"); %> </body> </html>
In Figure 4.9 you can see that three out of the five Response.Write() commands were rendered to the browser. Notice the times at which they were delivered to the browser. Can you see which two Writes are missing?
The first Write happens and is delivered to the browser when you execute the Response.Flush() method as is the second one with a lapse of five seconds between when the first and second Write. Notice that the third Write is missing from the browser window, but why? Simple. The Response.Clear() method disposed of everything that was still in the buffer. In other words, the buffer is like a container in which processed code is stored. If you use a flush, you dump the bucket to the browser. If you use a Clear(), you dump the bucket to the trash never to be seen again. Later, a Response.End() is used, which is just like a clear() except it completely stops page processing. Look at the generated HTML for this page. Do you notice anything peculiar about the tags that came after the Response.End()?
<html> <head> <title>HttpResponse</title> </head> <body> 2/6/2002 7:06:39 PM The First Response.Write() has executed.<BR> 2/6/2002 7:06:44 PM The Second Response.Write() has executed.<BR> 2/6/2002 7:06:54 PM The Fourth Response.Write() has executed.<BR>
The closing </body> and </html> tags are missing because the Response.End() isn't specific to stopping the processing of just ASP.NET but the entire HTTP stream of data. It basically dumps the bucket at that point and that's it. Nothing else gets processed.
What is a practical application for the buffer? One place we use it all the time and is a good example is on check-out pages of commerce applications we build. We have clients who send their credit card transactions to a third-party processing company and rely on this third-party processor's server to respond back to us indicating whether the card is accepted or declined. During this period of waiting, however, the visitor needs to be kept busy. Our technique is to build an HTML layer with a message that says "We're now processing your card." Then we flush the Buffer (dump the bucket) and send that message to the visitor's browser. Next, we send the credit card information to the third-party company and wait. When we get a reply from the transaction company we build code to hide the layer and do some fancy-schmancy stuff in the back end database depending on whether the card was accepted or declined. We either build a receipt page or a page with a message as to why the transaction was declined. Then we flush the buffer again and deliver the rest of what's in the bucket.
If we didn't have the buffer, the visitor would either be faced with a page that sat idle with no evidence of any activity and hope something was happening, or we'd be forced to jump through flaming hoops and redirect to different pages a bunch of times to accomplish the same thing. And visitors do not enjoy unexplained screen flashes and redirections. With the buffer, we can display a screen telling them what is happening and then deliver a response without any confusion.
I also want to add a thing or two about the Response.Write method. This was a highly used and abused method of writing data to traditional ASP pages. It was one of the only ways to dynamically write things into ASP pages.
This is not the case anymore, and with the proliferation of server controls such as the label used so far to display the example results, you will find yourself using Response.Write less and less. It is actually a bit out of place in the ASP.NET programming language because it really operates under the more traditional in-line, interpreted model than the event-oriented environment of ASP.NET. The Response.Write method doesn't allow you to affect other objects; it just does what it does, where it is, and that is that.
I must also mention the Response.Redirect method, as well. This is an oft-used method for transporting the user to another page or URL. The syntax for using this method is to simply place the desired location within the parentheses of the method call, enclosed in quotes if it is a string like the following example.
Response.Redirect("anotherpage.asp")
You can only use Response.Redirect if the HTML stream hasn't begun. In other words, if the buffer has begun to send HTML code to the browser, or if HTML code has been generated at all, using the Response.Redirect method causes an error.
As you can see, the Request and Response objects help you understand and carry on a conversation with the users of your web applications. These are critical tools in your toolbox and are objects you will be seeing over and over throughout the remainder of this book, as well as in your experience in programming in this wonderful language called ASP.NET.