【读书笔记】Web Forms

To run an ASP.NET web form, the ASP.NET engine reads the entire .aspx file, generates the corresponding objects, and fires a series of events. You react to these events using thoroughly object-oriented code.

Page Processing

  

Web applications execute on the server:

Web applications are stateless:

In other words, before the rendered HTML page is sent to the user, your web-page objects are destroyed and all client-specific information is discarded. This model lends itself well to highly scalable, heavily trafficked applications, but it makes it difficult to create a seamless user experience. ASP.NET includes several tools to help you bridge this gap; most notable is a persistence mechanism called view state, which automatically embeds information
about the page in a hidden field in the rendered HTML.

HTML Forms

If you’re familiar with HTML, you know that the simplest way to send client-side data to the server is using a <form> tag. Inside the <form> tag, you can place other <input> tags to represent basic user interface ingredients such as buttons, text boxes, list boxes, check boxes, and radio buttons.

For example, here’s an HTML page that contains two text boxes, two check boxes, and a submit button, for a total of five <input> tags:

   1: <html xmlns="http://www.w3.org/1999/xhtml">
   2: <head>
   3:     <title>Programmer Questionnaire</title>
   4: </head>
   5: <body>
   6:     <form method="post" action="page.aspx">
   7:         <div>
   8:             Enter your first name:
   9:             <input type="text" name="FirstName" />
  10:             <br />
  11:             Enter your last name:
  12:             <input type="text" name="LastName" />
  13:             <br /><br />
  14:             You program with:
  15:             <br />
  16:             <input type="checkbox" name="CS" />C#
  17:             <br />
  18:             <input type="checkbox" name="VB" />VB .NET
  19:             <br /><br />
  20:             <input type="submit" value="Submit" id="OK" />
  21:             </div>
  22:         </form>
  23:     </body>
  24: </html>

When the user clicks the submit button, the browser collects the current value of each control and pastes it together in a long string. This string is then sent back to the page indicated in the <form> tag (in this case, page.aspx) using an HTTP POST operation.


In this example, that means the web server might receive a request with this string of information:

FirstName=Matthew&LastName=MacDonald&CS=on&VB=on

The browser follows certain rules when constructing this string. Information is always sent as a series of name/value pairs separated by the ampersand (&) character. Each name/value pair is split with an equal (=) sign. Check boxes are left out unless they are checked, in which case the browser supplies the text on for the value.

Virtually all server-side programming frameworks add a layer of abstraction over the raw form data. They parse this string and expose it in a more useful way. For example, JSP, ASP, and ASP.NET all allow you to retrieve the value of a form control using a thin object layer. In ASP and ASP.NET, you can look up values by name in the Request.Form collection. If you change the previous page into an ASP.NET web form, you can use this approach with code like this:

   1:  
   2: string firstName = Request.Form["FirstName"];

This thin veneer over the actual POST message is helpful, but it’s still a long way from a true object-oriented framework. That’s why ASP.NET goes another step further. When a page is posted back to ASP.NET, it extracts the values, populates the Form collection (for backward compatibility with ASP code), and then configures the corresponding control objects. This means you can use the following much more intuitive syntax to retrieve information in an ASP.NET web form:

   1: string firstName = txtFirstName.Text;


This code also has the benefit of being typesafe. In other words, if you’re retrieving the state of the check box, you’ll receive a Boolean true or false value, instead of a string with the word on. In this way, developers are insulated from the quirks of HTML syntax.

■Note In ASP.NET, all controls are placed inside a single <form> tag. This tag is marked with the runat="server"
attribute, which allows it to work on the server side. ASP.NET does not allow you to create web forms that contain
more than one server-side form tag, although it is possible to create a page that posts to another page using a technique called cross-page posting.

Dynamic User Interface

The ASP.NET Event Model

Classic ASP uses a linear processing model. That means code on the page is processed from start to finish and is executed in order. Because of this model, classic ASP developers need to write a considerable amount of code even for simple pages.

ASP.NET provides a refreshing change with its event-driven model. In this model, you add controls to a web form and then decide what events you want to respond to. Each event handler is a discrete method, which keeps the page code tidy and organized. This model is nothing new, but until the advent of ASP.NET it has been the exclusive domain of windowed UI programming in rich client applications.


So, how do ASP.NET events work? It’s surprisingly straightforward. Here’s a brief outline:


1. Your page runs for the first time. ASP.NET creates page and control objects, the initialization code executes, and then the page is rendered to HTML and returned to the client. The page objects are also released from server memory.


2. At some point, the user does something that triggers a postback, such as clicking a button. At this point, the page is submitted with all the form data.


3. ASP.NET intercepts (拦截) the returned page and re-creates the page objects, taking care to return them to the state they were in the last time the page was sent to the client. (Use ViewState [by Fang] )

  

4. Next, ASP.NET checks what operation triggered the postback, and it raises the appropriate events (such as Button.Click), which your code can react to. Typically, at this point you’ll perform some server-side operation (such as updating a database or reading data from a file) and then modify the control objects to display new information.


5. The modified page is rendered to HTML and returned to the client. The page objects are released from memory. If another postback occurs, ASP.NET repeats the process in steps 2 through 4.


In other words, ASP.NET doesn’t just use the form data to configure the control objects for your page. It also uses it to decide what events to fire. For example, if it notices the text in a text box has changed since the last postback, it raises an event to notify your page. It’s up to you whether you want to respond to this event.

Automatic Postbacks

To use automatic postback, you simply need to set the AutoPostBack property of a web control to true (the default is false, which ensures optimum performance if you don’t need to react to a change event). When you do, ASP.NET uses the client-side abilities of JavaScript to bridge the gap between client-side and server-side code.

Here’s how it works: if you create a web page that includes one or more web controls that are configured to use AutoPostBack, ASP.NET adds a JavaScript function to the rendered HTML page named __doPostBack(). When called, it triggers a postback, posting the page back to the web server with all the form information.


ASP.NET also adds two hidden input fields that the __doPostBack() function uses to pass information back to the server. This information consists of the ID of the control that raised the event and any additional information that might be relevant. These fields are initially empty, as shown here:

   1: <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
   2: <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />


The __doPostBack() function has the responsibility for setting these values with the appropriate information about the event and then submitting the form. A sample __doPostBack() function is shown here:

   1: <script language="text/javascript">
   2: <!--
   3: function __doPostBack(eventTarget, eventArgument) {
   4:     var theForm = document.form1;
   5:     theform.__EVENTTARGET.value = eventTarget;
   6:     theform.__EVENTARGUMENT.value = eventArgument;
   7:     theform.submit();
   8: }
   9: // -->
  10: </script>

Remember, ASP.NET generates the __doPostBack() function automatically. This code grows lengthier as you add more AutoPostBack controls to your page, because the event data must be set for each control.

Finally, any control that has its AutoPostBack property set to true is connected to the __doPostBack() function using the onclick or onchange attribute. These attributes indicate what action the browser should take in response to the client-side JavaScript events onclick and onchange.


The following example shows the rendered HTML for a list control named lstCountry, which posts back automatically. Whenever the user changes the selection in the list, the client-side onchange event fires. The browser then calls the __doPostBack() function, which sends the page back to the server.

   1: <select id="lstCountry" onchange="__doPostBack('lstCountry','')" language="javascript">

In other words, ASP.NET automatically changes a client-side JavaScript event into a server-side ASP.NET event, using the __doPostBack() function as an intermediary. If you’re a seasoned ASP developer, you may have manually created a solution like this for traditional ASP web pages. ASP.NET handles these details for you automatically, simplifying life a great deal.

  

  

View State

  

Every time your page is posted back to the server, ASP.NET receives all the information that the user has entered in any <input> controls in the <form> tag. ASP.NET then loads the web page in its original state (based on the layout and defaults you’ve defined in the .aspx file) and tweaks the page according to this new information.

The problem is that in a dynamic web form, your code might change a lot more. For example, you might programmatically change the color of a heading, modify a piece of static text, hide or show a panel of controls, or even bind a full table of data to a grid. All these actions change the page from its initial state. However, none of them is reflected in the form data that’s posted back. That means this information will be lost after every postback. Traditionally, statelessness has been overcome with the use of simple cookies, session-based cookies, and various other workarounds. All of these mechanisms require homemade (and sometimes painstaking)
measures.

To deal with this limitation, ASP.NET has devised its own integrated state serialization mechanism. Essentially, once your page code has finished running (and just before the final HTML is rendered and sent to the client), ASP.NET examines all the properties of all the controls on your page. If any of these properties has been changed from its initial state, ASP.NET makes a note of this information in a name/value collection. Finally, ASP.NET takes all the information it has amassed and then serializes it as a Base64 string. (A Base64 string ensures that there aren’t any special characters that wouldn’t be valid HTML.) The final string is inserted in the <form> section of the page as
a new hidden field.

The next time the page is posted back, ASP.NET follows these steps:


1. ASP.NET re-creates the page and control objects based on its defaults (as defined in the .aspx file). Thus, the page has the same state that it had when it was first requested.


2. Next, ASP.NET deserializes the view state information and updates all the controls. This returns the page to the state it was in before it was sent to the client the last time.

3. Finally, ASP.NET adjusts the page according to the posted back form data. For example, if the client has entered new text in a text box or made a new selection in a list box, that information will be in the Form collection and ASP.NET will use it to tweak the corresponding controls. After this step, the page reflects the current state as it appears to the user.

4. Now your event-handling code can get involved. ASP.NET triggers the appropriate events, and your code can react to change the page, move to a new page, or perform a completely different operation.

Using view state is a great solution because server resources can be freed after each request, thereby allowing for scalability to support hundreds or thousands of requests without bogging the server down. However, it still comes with a price. Because view state is stored in the page, it results in a larger total page size. This affects the client doubly, because the client not only needs to receive a larger page, but the client also needs to send the hidden view state data back to the server with the next postback. Thus, it takes longer both to receive and post the page. For simple pages, this overhead is minimal, but if you configure complex, data-heavy controls such as the GridView,
the view state information can grow to a size where it starts to exert a toll. In these cases, you can disable view state for a control by setting its EnableViewState property to false. However, in this case you need to reinitialize the control with each postback.

■Note Even if you set EnableViewState to false, the control can still hold onto a smaller amount of view state
information that it deems critical for proper functioning. This privileged view state information is known as control
state
, and it can never be disabled. However, in a well-designed control the size required for control state will be
significantly smaller than the size of the entire view state.

ASP.NET uses view state only with page and control properties. ASP.NET doesn’t take the same steps with member variables and other data you might use. However, as you’ll learn later in this book, you can place other types of data into view state and retrieve this information manually at a later time.


Figure 3-2 provides an end-to-end look at page requests that puts all these concepts together.

image

image

View State “Under the Hood”

If you look at the rendered HTML for an ASP.NET page, you can easily find the hidden input field with the view state information. The following example shows a page that uses a simple Label web control and sets it with a dynamic “Hello, world” message:

   1: <html>
   2: <head>
   3: <title>Hello World 
   4: Page</title>
   5: </head>
   6: <body>
   7: <form name="form1" 
   8: method="post" action="WebForm1.aspx" id="form1">
   9: <div>
  10: <input 
  11: type="hidden" name="__VIEWSTATE" 
  12: id="__VIEWSTATE"
  13: value="/wEPDwUKLTE2MjY5MTY1NQ9kFgICAw9kFgICAQ8PFgIeBFRleHQFDEhlbGxv
  14: IFdvcmxkIWRkZPsbiNOyNAufEt7OvNIbVYcGWHqf" 
  15: />
  16: </div>
  17: <div>
  18: <input type="submit" name="Button1" 
  19: value="Button" id="Button1" />
  20: <span id="lbl">Hello, world</span>
  21: </div>
  22: </form>
  23: </body>
  24: </html>

The view state string isn’t human readable—it just looks like a series of random characters.
However, it’s important to note that a user who is willing to go to a little work can interpret this data quite easily. Here’s a snippet of .NET code that does the job and writes the decoded information to a web page:

   1: // viewStateString contains the view state information.
   2: // Convert the Base64 string to an ordinary array of bytes
   3: // representing ASCII characters.
   4: byte[] stringBytes = Convert.FromBase64String(viewStateString);
   5: // Deserialize and display the string.
   6: string decodedViewState = System.Text.Encoding.ASCII.GetString(stringBytes);
   7: lbl.Text = decodedViewState;

In order to test this web page, you’ll need to copy a view state string from an existing web page
(using the View Source command in your web browser). Or, you can retrieve the view state string for
the current web page using server-side code like this:

   1: string viewStateString = Request["__VIEWSTATE"];

When you look at the decoded view state string, you’ll see something like this:


? -162691655dd-Text Hello, worldddd????4 ?????U?Xz?

As you can see, the control text is clearly visible (along with some unprintable characters that render as blank boxes). This means that, in its default implementation, view state isn’t a good place to store sensitive information that the client shouldn’t be allowed to see—that sort of data should stay on the server. Additionally, you shouldn’t make decisions based on view state that could compromise your application if the client tampers with the view state data.

Fortunately, it’s possible to tighten up view state security quite a bit. You can enable automatic hash codes to prevent view state tampering, and you can even encrypt view state to prevent it from being decoded. These techniques raise hidden fields from a clumsy workaround to a much more robust and respectable piece of infrastructure.

View State Chunking

The size of the hidden view state field has no limit. However, some proxy servers and firewalls refuse to let pages through if they have hidden fields greater than a certain size. To circumvent this problem, you can use view state chunking, which automatically divides view state into multiple fields to ensure that no hidden field exceeds a size threshold you set.

To use view state, you simply need to set the maxPageStateFieldLength attribute of the <pages> element in the web.config file. This specifies the maximum view state size, in bytes.

Here’s an example that caps view state at 1 KB:

   1: <configuration>
   2:     <system.web>
   3:         <pages maxPageStateFieldLength = "1024" />
   4:     </system.web>
   5: </configuration>

When you request a page that generates a view state larger than this, several hidden input fields will be created:

   1: <input type="hidden" name="__VIEWSTATEFIELDCOUNT" value="3" />
   2: <input type="hidden" name="__VIEWSTATE" value="..." />
   3: <input type="hidden" name="__VIEWSTATE1" value="..." />
   4: <input type="hidden" name="__VIEWSTATE2" value="..." />


Remember, view state chunking is simply a mechanism for avoiding problems with certain proxies (which is a relatively rare occurrence). View state chunking does not improve performance (and adds a small amount of extra serialization overhead). As a matter of good design, you should strive to include as little information in view state as possible, which ensures the best performance.

Web Forms Processing Stages

The following list shows the major stages in the process flow of an ASP.NET page:


• Page framework initialization
• User code initialization
• Validation
• Event handling
• Automatic data binding
• Cleanup

Remember, these stages occur independently for each web request. Figure 3-4 shows the order in which these stages unfold. More stages exist than are listed here, but those are typically used for programming your own ASP.NET controls and aren’t handled directly by the page.

image

Page Framework Initialization

This is the stage in which ASP.NET first creates the page. It generates all the controls you have defined with tags in the .aspx web page. In addition, if the page is not being requested for the first time (in other words, if it’s a postback), ASP.NET deserializes the view state information and applies it to all the controls.

At this stage, the Page.Init event fires. However, this event is rarely handled by the web page, because it’s still too early to perform page initialization. That’s because the control objects may not be created yet and because the view state information isn’t loaded.

  

User Code Initialization

At this stage of the processing, the Page.Load event is fired. Most web pages handle this event to perform any required initialization (such as filling in dynamic text or configuring controls).
The Page.Load event always fires, regardless of whether the page is being requested for the first time or whether it is being requested as part of a postback. Fortunately, ASP.NET provides a way to allow programmers to distinguish between the first time the page is loaded and all subsequent loads.
Why is this important?

First, since view state is maintained automatically, you have to fetch your data from a dynamic data source only on the first page load. On a postback, you can simply sit back, relax, and let ASP.NET restore the control properties for you from the view state. This can provide a dramatic performance boost if the information is expensive to re-create (for example, if you need to query it from a database).

Second, there are also other scenarios, such as edit forms and drill-down pages, in which you need the ability to display one interface on a page’s first use and a different interface on subsequent loads.


To determine the current state of the page, you can check the IsPostBack property of the page,
which will be false the first time the page is requested. Here’s an example:

   1: if (!IsPostBack)
   2: {
   3:     // It's safe to initialize the controls for the first time.
   4:     FirstName.Text = "Enter your name here";
   5: }

■Note It’s a common convention to write Page.IsPostBack instead of just IsPostBack. This longer form works
because all web pages are server controls, and all server controls include a Page property that exposes the current page. In other words, Page.IsPostBack is the same as IsPostBack—some developers simply think the first version is easier to read. Which approach you use is simply a matter of preference.


Remember, view state stores every changed property. Initializing the control in the Page.Load event counts as a change, so any control value you touch will be persisted in view state, needlessly enlarging the size of your page and slowing transmission times. To streamline your view state and keep page sizes small, avoid initializing controls in code. Instead, set the properties in the control tag (either by editing the tag by hand in source view or by using the Properties window). That way, these details won’t be persisted in view state. In cases where it really is easier to initialize the control in code, consider disabling view state for the control by setting EnableViewState to false and initializing the control every time the Page.Load event fires, regardless of whether the current request is a postback.

Validation

  

ASP.NET includes validation controls that can automatically validate other user input controls and display error messages. These controls fire after the page is loaded but before any other events take place. However, the validation controls are for the most part self-sufficient, which means you don’t need to respond to the validation events. Instead, you can just examine whether the page is valid (using the Page.IsValid property) in another event handler.

  

Event Handling

At this point, the page is fully loaded and validated. ASP.NET will now fire all the events that have taken place since the last postback.

For the most part, ASP.NET events are of two types:


Immediate response events: These include clicking a submit button or clicking some other button, image region, or link in a rich web control that triggers a postback by calling the __doPostBack() JavaScript function.


Change events: These include changing the selection in a control or the text in a text box. These events fire immediately for web controls if AutoPostBack is set to true. Otherwise, they fire the next time the page is posted back.


As you can see, ASP.NET’s event model is still quite different from a traditional Windows environment.
In a Windows application, the form state is resident in memory, and the application runs continuously. That means you can respond to an event immediately. In ASP.NET, everything occurs in stages, and as a result events are sometimes batched together.
For example, imagine you have a page with a submit button and a text box that doesn’t post back automatically. You change the text in the text box and then click the submit button. At this point, ASP.NET raises all of the following events (in this order):


• Page.Init
• Page.Load
• TextBox.TextChanged
• Button.Click
• Page.PreRender
• Page.Unload


Remembering this bit of information can be essential in making your life as an ASP.NET programmer easier. There is an upside and a downside to the event-driven model. The upside is that the event model provides a higher level of abstraction, which keeps your code clear of boilerplate code for maintaining state. The downside is that it’s easy to forget that the event model is really just an emulation. This can lead you to make an assumption that doesn’t hold true (such as expecting information to remain in member variables) or a design decision that won’t perform well (such as storing vast amounts of information in view state).

Automatic Data Binding

When you use the data source controls, ASP.NET automatically performs updates and queries against your data source as part of the page life cycle.
Essentially, two types of data source operations exist. Any changes (inserts, deletes, or updates) are performed after all the control events have been handled but just before the Page.PreRender event fires.

Then, after the Page.PreRender event fires, the data source controls perform their queries and insert the retrieved data into any linked controls. This model makes instinctive sense, because if queries were executed before updates, you could end up with stale data in your web page. However, this model also introduces a necessary limitation—none of your other event handlers will have access to the most recent data, because it hasn’t been retrieved yet.

This is the last stop in the page life cycle. Historically, the Page.PreRender event is supposed to signify the last action before the page is rendered into HTML (although, as you’ve just learned, some data binding work can still occur after the prerender stage). During the prerender stage, the page and control objects are still available, so you can perform last-minute steps such as storing additional information in view state.
 

Cleanup

At the end of its life cycle, the page is rendered to HTML. After the page has been rendered, the real cleanup begins, and the Page.Unload event is fired. At this point, the page objects are still available, but the final HTML is already rendered and can’t be changed.
Remember, the .NET Framework has a garbage collection service that runs periodically to release memory tied to objects that are no longer referenced. If you have any unmanaged resources to release, you should make sure you do this explicitly in the cleanup stage or, even better, before. When the garbage collector collects the page, the Page.Disposed event fires. This is the end of the road for the web page.

The Page As a Control Container

 

Showing the Control Tree

  

ASP.NET models the entire page using control objects, including elements that don’t correspond to server-side content. For example, if you have one server control on a page, ASP.NET will create a LiteralControl that represents all the static content before the control and will create another LiteralControl that represents the content after it. Depending on how much static content you have and how you break it up between other controls, you may end up with multiple LiteralControl objects.

ASP.NET renders a page hierarchically. It directly renders only the top level of controls. If these controls contain other controls, they provide their own Controls properties, which provide access to their child controls. In the example page, as in all ASP.NET web forms, all the controls are nested inside the <form> tag. This means you need to inspect the Controls collection of the HtmlForm class to get information about the server controls on the page.

The Page Header

As you’ve seen, you can transform any HTML element into a server control with the runat="server" attribute, and a page can contain an unlimited number of HTML controls. In addition to the controls you add, a web form can also contain a single HtmlHead control, which provides server-side access to the <head> tag.
The Visual Studio default is to always make the <head> tag into a server-side control.

As with other server controls, you can use the HtmlHead control to programmatically change the content that’s rendered in the <head> tag. The difference is that the <head> tag doesn’t correspond to actual content you can see in the web page. Instead, it includes other details such as the title, metadata tags (useful for providing keywords to search engines), and stylesheet references.

To change any of these details, you use one of a small set of members in the HtmlHead class. They include the following:


Title: This is the title of the HTML page, which is usually displayed in the browser’s title bar. You can modify this at runtime.

StyleSheet: This provides an IStyleSheet object that represents inline styles defined in the header. You can also use the IStyleSheet object to create new style rules dynamically, by writing code that calls its CreateStyleRule() and RegisterStyle() methods.

Controls: You can add or remove metadata tags programmatically using this collection and the HtmlMeta control class.


Here’s an example that sets title information and metadata tags dynamically:

   1: Page.Header.Title = "Dynamically Titled Page";
   2: // Define a metadata tag with description information.
   3: HtmlMeta metaDescription = new HtmlMeta();
   4: metaDescription.Name = "description";
   5: metaDescription.Content = "A great website to learn .NET";
   6: // Add it.
   7: Page.Header.Controls.Add(metaDescription);
   8: // Define and add a second metadata tag.
   9: HtmlMeta metaKeywords = new HtmlMeta();
  10: metaKeywords.Name = "keywords";
  11: metaKeywords.Content = ".NET, C#, ASP.NET";
  12: Page.Header.Controls.Add(metaKeywords);

Dynamic Control Creation

Using the Controls collection, you can create a control and add it to a page programmatically. Here’s
an example that generates a new button and adds it to a Panel control on the page:

   1: protected void Page_Load(object sender, System.EventArgs e)
   2: {
   3:     // Create a new button object.
   4:     Button newButton = new Button();
   5:     // Assign some text and an ID so you can retrieve it later.
   6:     newButton.Text = "* Dynamic Button *";
   7:     newButton.ID = "newButton";
   8:     // Add the button to a Panel.
   9:     Panel1.Controls.Add(newButton);
  10: }

You can execute this code in any event handler. However, because the page is already created, this code always adds the new control at the end of the collection. In this example, that means the new button will end up at the bottom of the Panel control.
To get more control over where a dynamically added control is positioned, you can use a PlaceHolder. A PlaceHolder is a control that has no purpose except to house other controls. If you don’t add any controls to the Controls collection of the PlaceHolder, it won’t render anything in the final web page. However, Visual Studio gives a default representation that looks like an ordinary label at design time, so you can position it exactly where you want. That way, you can add a dynamic control between other controls.

   1: // Add the button to a PlaceHolder.
   2: PlaceHolder1.Controls.Add(newButton);

When using dynamic controls, you must remember that they will exist only until the next postback.
ASP.NET will not re-create a dynamically added control. If you need to re-create a control multiple times, you should perform the control creation in the Page.Load event handler. This has the additional benefit of allowing you to use view state with your dynamic control.

Even though view state is normally restored before the Page.Load event, if you create a control in the handler for the Page.Load event, ASP.NET will apply any view state information that it has after the Page.Load event
handler ends. This process is automatic.
If you want to interact with the control later, you should give it a unique ID. You can use this ID to retrieve the control from the Controls collection of its container. You can find the control using recursive searching logic, as demonstrated in the control tree example, or you can use the static Page.FindControl() method, which searches the entire page for the control with the ID you specify.
Here’s an example that searches for the dynamically added control with the FindControl() method and then removes it:

   1: protected void cmdRemove_Click(object sender, System.EventArgs e)
   2: {
   3:     // Search for the button, no matter what level it's at.
   4:     Button foundButton = (Button)Page.FindControl("newButton"); 
   5:     // Remove the button.
   6:     if (foundButton != null)
   7:     {
   8:         foundButton.Parent.Controls.Remove(foundButton);
   9:     }
  10: }


Dynamically added controls can handle events. All you need to do is attach an event handler using delegate code. You must perform this task in your Page.Load event handler. As you learned earlier, all control-specific events are fired after the Page.Load event. If you wait any longer, the event handler will be connected after the event has already fired, and you won’t be able to react to it any longer.

   1: // Attach an event handler to the Button.Click event.
   2: newButton.Click += dynamicButton_Click); 

Dynamic control creation is particularly powerful when you combine it with user controls (reusable blocks of user interface that can combine a group of controls and HTML).

The Page Class

In fact, all web forms are actually instances of the ASP.NET Page class, which is found in the System.Web.UI namespace.

You may have already figured this out by noticing that every code-behind class explicitly derives from System.Web.UI.Page. This means that every web form you create is equipped with an enormous amount of out-of-the-box functionality. The FindControl() method and the IsPostBack property are two examples you’ve seen so far. In addition, deriving from the Page class gives your code the following extremely useful properties:
• Session
• Application
• Cache
• Request
• Response
• Server
• User
• Trace
Many of these properties correspond to intrinsic objects that you could use in classic ASP web pages. However, in classic ASP you accessed this functionality through built-in objects that were available at all times. In ASP.NET, each of these built-in objects actually corresponds to a Page property that exposes an instance of a full-featured class.

Session, Application, and Cache

The Session object is an instance of the System.Web.SessionState.HttpSessionState class. It’s designed to store any type of user-specific data that needs to persist between web-page requests.
The Session object provides dictionary-style access to a set of name/value pairs that represents the user’s data for that session. Session state is often used to maintain things such as the user’s name, the user’s ID, a shopping cart, or various other elements that are discarded when a given user is no longer accessing pages on the website.

The Application object is an instance of the System.Web.HttpApplicationState class. Like the Session object, it’s also a name/value dictionary of data. However, this data is global to the entire application.


Finally, the Cache object is an instance of the System.Web.Caching.Cache class. It also stores global information, but it provides a much more scalable storage mechanism because ASP.NET can remove objects if server memory becomes scarce. Like the other state collections, it’s essentially a name/value collection of objects, but you can also set specialized expiration policies and dependencies for each item.


Request

The Request object is an instance of the System.Web.HttpRequest class. This object represents the values and properties of the HTTP request that caused your page to be loaded. It contains all the URL parameters and all other information sent by a client. Much of the information provided by the Request object is wrapped by higher-level abstractions (such as the ASP.NET web control model), so it isn’t nearly as important as it was in classic ASP. However, you might still use the Request object to find out what browser the client is using or to set and examine cookies.

Response

The Response object is an instance of the System.Web.HttpResponse class, and it represents the web server’s response to a client request. In classic ASP, the Response object was the only way to programmatically send HTML text to the client. Now server-side controls have nested, objectoriented methods for rendering themselves. All you have to do is set their properties. As a result, the Response object doesn’t play nearly as central a role.
The HttpResponse does still provide some important functionality—namely, cookie features and the Redirect() method. The Redirect() method allows you to send the user to another page.
Here’s an example:

   1: // You can redirect to a file in the current directory.
   2: Response.Redirect("newpage.aspx");
   3: // You can redirect to another website.
   4: Response.Redirect(http://www.prosetech.com);

The Difference Between “Response.Redirect()” and “Server.Transfer()”


The Redirect() method requires a round-trip. Essentially, it sends a message to the browser that instructs it to request a new page.


If you want to transfer the user to another web form in the same web application, you can use a faster approach with the Server.Transfer() method.

However, Server.Transfer has some quirks. Because the redirection happens on the server side, the original URL remains in the client’s web browser. Effectively, the browser has no way of knowing that it’s actually displaying a different page.This limitation leads to a problem if the client refreshes or bookmarks the page.

Also, Server.Transfer() is unable to transfer execution to a non-ASP.NET page or a web page in another web application or on another web server.

The Transfer() method is the quickest way to redirect the user to another page in your application. When you use this method, a round-trip is not involved. Instead, the ASP.NET engine simply loads the new page and begins processing it. As a result, the URL that’s displayed in the client’s browser won’t change.

■Tip Another way also exists to get from one page to the next—cross-page posting. Using this technique, you can create a page that posts itself to another page, which allows you to effectively transfer all the view state information and the contents of any controls.

Server

The Server object is an instance of the System.Web.HttpServerUtility class. It provides a handful of miscellaneous helper methods and properties.

HtmlEncode() and HtmlDecode()
Changes an ordinary string into a string with legal HTML characters (and back again).

UrlEncode() and UrlDecode()
Changes an ordinary string into a string with legal URL characters (and back again).


UrlTokenEncode() and UrlTokenDecode()
Performs the same work as UrlEncode() and UrlDecode(), except they work on a byte array that contains Base64-encoded data.

MapPath()

Returns the physical file path that corresponds to a specified virtual file path on the web server.

The MapPath() method is another useful method of the Server object. For example, imagine you want to load a file named info.txt from the current virtual directory. Instead of hard-coding the path, you can use Server.MapPath() to convert the relative path to your web application into a full physical path. Here’s an example:

   1: string physicalPath = Server.MapPath("info.txt");
   2: // Now open the file.
   3: StreamReader reader = new StreamReader(physicalPath);
   4: // (Process the file here.)
   5: reader.Close();

  

User 

The User object represents information about the user making the request of the web server, and it allows you to test that user’s role membership.
The User object implements System.Security.Principal.IPrincipal. The specific class depends on the type of authentication you’re using. For example, you can authenticate a user based on Windows account information using IIS or through cookie-based authentication with a dedicated login page. However, it’s important to realize that the User object provides useful information only if your web application is performing some sort of authentication that restricts anonymous users.

Trace

The Trace object is a general-purpose tracing tool (and an instance of the System.Web.TraceContext class). It allows you to write information to a log that is scoped at the page level. This log has detailed timing information so that not only can you use the Trace object for debugging but you can also use it for performance monitoring and timing. Additionally, the trace log shows a compilation of miscellaneous information, grouped into several sections.

原文地址:https://www.cnblogs.com/fangwenyu/p/1608788.html