ASP.NET AJAX Programmer’s Reference - Chapter 21 pot

68 184 0
ASP.NET AJAX Programmer’s Reference - Chapter 21 pot

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Page Life Cycle and Asynchronous Partial Page Rendering The main goal of this and the next few chapters is to help you gain a solid understanding of the ASP.NET AJAX asynchronous page postback or partial-page-rendering-request-processing infra- structure. This infrastructure consists of two groups of components: ❑ Server-side components: This group includes the ScriptManager , UpdatePanel , PageRequestManager , and ScriptRegistrationManager classes. ❑ Client-side components: This group includes the PageRequestManager , WebRequest , WebRequestExecutor , WebRequestManager , XMLHttpExecutor , and Application classes, among others. Note that both the server and client sides contain a component named PageRequestManager . Even though they have the same name, they are two different components defined in two different frameworks. One is defined in the ASP.NET AJAX server-side framework while the other is defined in the ASP.NET AJAX client-side framework. For ease of reference, I’ll refer to the one defined in the server-side framework as the server-side PageRequestManager and the other as the client-side PageRequestManager . These components are at the heart of ASP.NET AJAX partial page rendering, which, as you’ll see later, is the result of the communications between the client- side and server-side PageRequestManager components. As their names suggest, they’re the ones that are responsible for managing and processing asynchronous partial-page-rendering requests. Here is how these two components work together. The current client-side PageRequestManager instance makes an asynchronous page postback request to the server. The current server-side PageRequestManager instance picks up and processes the request and sends the reponse text back to the client. The current client-side PageRequestManager instance then picks up and processes the response text and updates the regions of the page enclosed within the specified UpdatePanel server controls. c21.indd 965c21.indd 965 8/20/07 8:37:01 PM8/20/07 8:37:01 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering 966 Your server-side code cannot directly access the current server-side PageRequestManager instance. Your code gets to interact with the current server-side PageRequestManager instance via the current ScriptManager server control, as you’ll see later in this chapter. Your client-side code, on the other hand, can directly access the current client-side PageRequestManager instance. This will all be cleared up later in this and the following chapters. Processing a Request When an HTTP request — be it synchronous, asynchronous, partial-page-update, or normal postback — for an ASP.NET Web page arrives, the ASP.NET framework parses the requested page into a dynamically generated class that inherits the ASP.NET Page class. By default, the name of this class consists of two parts separated by an underscore character ( _ ). The first part is the name of the file that contains the page and the second part is the string aspx . For example, if the requested page is in a file named default .aspx , ASP.NET parses the content of this file into a dynamically generated class named default_aspx that inherits the Page class. All ASP.NET dynamically generated classes, such as default_aspx , belong to a standard namespace named ASP . As a matter of fact, Visual Studio provides IntelliSense support for this namespace and its constituent dynamically generated classes. To see this, open the file that contains the code-behind file for an ASP.NET Web page (for example, the default.aspx.cs ) in Visual Studio and type the first letter of the ASP namespace, that is, the letter A. You should see the popup that displays all the namespaces whose names begin with that letter, including the ASP namespace. Now, if you select ASP from this popup and type the dot character ( . ) you should see the name of the dynamically generated class (for example, default_aspx ) associated with the current Web page. After parsing the requested page into a dynamically generated class that inherits from the ASP.NET Page class, the ASP.NET framework temporarily stores the code for this class in a source file a couple of directories below the directory named after the current Web application, in a standard directory named Temporary ASP.NET Files , under the directory on your machine where the .NET framework is installed: %windir%\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\ ajaxenabledwebsite11\de910baf\54181126 The name of this source file follows this format: App_Web_FileName.aspx.RandomHash.0.cs , where the FileName is the name of the .aspx file and the RandomHash is a randomly generated hash value that ensures the uniqueness of the source-file name. Figure 21-1 shows an example that represents this file structure for an ASP.NET application named AjaxEnabledWebSite11. This Web application is a very simple one that consists of a single page named default.aspx , as shown in the following code listing. The file named App_Web_default.aspx.cdcab7d2.a5hjdn-i.0 shown in Figure 21-1 contains the source code for the ASP.default_aspx class that represents the default.aspx file. c21.indd 966c21.indd 966 8/20/07 8:37:02 PM8/20/07 8:37:02 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering 967 <%@ Page Language=”C#” %> <script runat=”server”> void SubmitCallback(object sender, EventArgs e) { Info.Text = TextBox1.Text; } </script> <html xmlns=”http://www.w3.org/1999/xhtml”> <body> <form id=”form1” runat=”server”> <asp:ScriptManager ID=”ScriptManager1” runat=”server” /> <asp:UpdatePanel runat=”server” ID=”UpdatePanel1”> <ContentTemplate> Enter text: <asp:TextBox runat=”server” ID=”TextBox1” /> <asp:Button runat=”server” ID=”Button1” Text=”Submit” OnClick=”SubmitCallback” /><br /> <asp:Label runat=”server” ID=”Info” /> </ContentTemplate> </asp:UpdatePanel> </form> </body> </html> If you’re curious to see what this dynamically generated class looks like, go to the previously mentioned directory and open the file that contains the source code for this class in your favorite editor. For example, the file associated with the preceding page contains the following source code (note that I’ve cleaned it up for presentation purposes): As I said earlier, the ASP.NET compilation system temporarily stores the source code in the previously mentioned source file. Therefore, if you want the file to remain in the directory so you can open it in your favorite editor, you must run the page in debug mode to instruct ASP.NET not to delete the file. using System; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.HtmlControls; namespace ASP { public class default_aspx : Page { protected ScriptManager ScriptManager1; protected TextBox TextBox1; protected Button Button1; protected Label Info; protected UpdatePanel UpdatePanel1; protected HtmlForm form1; . . . (continued) c21.indd 967c21.indd 967 8/20/07 8:37:02 PM8/20/07 8:37:02 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering 968 private UpdatePanel @__BuildControlUpdatePanel1() { . . . } private HtmlForm @__BuildControlform1() { . . . } private void @__BuildControlTree(default_aspx @__ctrl) { IParserAccessor @__parser = ((IParserAccessor)(@__ctrl)); @__parser.AddParsedSubObject( new LiteralControl(“<html xmlns=\”http://www.w3.org/1999/xhtml\”>”)); @__parser.AddParsedSubObject(new LiteralControl(“\r\n<body>\r\n “)); HtmlForm @__ctrl2 = this.@__BuildControlform1(); @__parser.AddParsedSubObject(@__ctrl2); @__parser.AddParsedSubObject( new LiteralControl(“\r\n</body>\r\n</html>\r\n”)); } protected override void FrameworkInitialize() { base.FrameworkInitialize(); this.@__BuildControlTree(this); } } } Figure 21-1 The ASP.NET framework then dynamically compiles the content of the source file that contains the dynamically generated class into an assembly, stores the assembly in the same directory as the source file, and deletes the source file afterward. If you run the application in debug mode, the ASP.NET framework will not delete the source file after the compilation. As I mentioned earlier, this will enable you to open the file in your favorite editor and study its content. The name of this assembly (continued) c21.indd 968c21.indd 968 8/20/07 8:37:02 PM8/20/07 8:37:02 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering 969 follows the naming convention App_Web_FileName.aspx.RandomHash.0.dll , where FileName is the name of the .aspx file and RandomHash is a randomly generated hash value that ensures the uniqueness of the DLL file name. For example, in the case of Figure 21-1 , the DLL’s name is App_Web_default.aspx.cdcab7d2.a5hjdn-i.dll . The ASP.NET Framework then loads this assembly — keep in mind that it contains the dynamically generated class — into the application domain where the current application is running, dynamically instantiates an instance of this compiled class, and calls the ProcessRequest method on this instance. For ease of reference, I’ll refer to this instance as the Page object or the Page , because this is an instance of a class that inherits the ASP.NET Page class. You can think of this instance (the Page object) as the ASP.NET representation of the requested Web page. It inherits the ProcessRequest method from the ASP.NET Page class. As the name suggests, this method processes the current request. The call into this method causes the Page object to start its life cycle, which consists of different phases. The best way to understand the ASP.NET AJAX asynchronous page postback or partial-rendering-request-processing infrastructure and its constituent components is to follow the Page object as it goes through its life cycle phases. The Page Life Cycle Listing 21-1 presents the internal implementation of the ProcessRequest method of the ASP.NET Page class. As you can see, this method consists of a bunch of method calls, each of which defines a particular phase of the Page object’s life cycle, as discussed in the following sections. Figure 21-2 presents the flowchart associated with the ProcessRequest method. Keep this flowchart in mind as you’re reading through this chapter. Listing 21-1: The ProcessRequest Method of the Page Class public void ProcessRequest(HttpContext context) { this._context = context; this.RetrievePostedData(); if (this.MaintainScrollPositionOnPostBack) this.LoadScrollPosition(); this.PerformPreInit(); this.InitRecursive(null); this.OnInitComplete(EventArgs.Empty); if (this.IsPostBack) { this.LoadAllState(); this.ProcessPostData(this._requestValueCollection, true); } this.OnPreLoad(EventArgs.Empty); this.LoadRecursive(); (continued) c21.indd 969c21.indd 969 8/20/07 8:37:03 PM8/20/07 8:37:03 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering 970 Listing 21-1 (continued) if (this.IsPostBack) { this.ProcessPostData(this._leftoverPostData, false); this.RaiseChangedEvents(); this.RaisePostBackEvent(this._requestValueCollection); } this.OnLoadComplete(EventArgs.Empty); this.PreRenderRecursive(); this.PerformPreRenderComplete(); this.SaveAllState(); this.OnSaveStateComplete(EventArgs.Empty); this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output)); } IsPostBack IsPostBack MaintainScrollPosition RetrievePostData LoadScrollPosition LoadControlStateLoadViewState LoadPostData PerformPreInit InitRecursive InitComplete LoadPostData (second try)RaisePostDataChangedEvent RaisePostBackEvent IsPostBack PreLoad LoadRecursive LoadComplete PreRenderRecursive PreRenderComplete SaveControlState SaveViewState SaveStateComplete Render Yes Yes Yes Yes Figure 21-2 c21.indd 970c21.indd 970 8/20/07 8:37:03 PM8/20/07 8:37:03 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering 971 Keep in mind that our goal in this chapter is to follow the Page object through its life cycle phases in order to understand the ASP.NET AJAX asynchronous page postback or partial-page-rendering-request- processing infrastructure and its constituent server-side and client-side components. As discussed in the previous chapter, an ASP.NET Web page enabled for partial page rendering contains a single instance of the ScriptManager server control and one or more instances of the UpdatePanel server controls. I’ll begin with the first request that the requesting browser makes to the server to visit an ASP.NET Web page enabled for partial page rendering. This first request is an HTTP GET request that downloads the Web page for the first time. Obviously this first request is not a postback or asynchronous postback request. I’ll first follow the Page object through its life cycle phases to process this very first request, even though it is not an asynchronous postback request because the first request instantiates and initial- izes many of the components that come into play in the subsequent asynchronous page postback requests to the same Web page. The First Visit to a Partial-Page-Rendering- Enabled Web Page As just discussed, to visit for the first time an ASP.NET Web page enabled for partial page rendering, the browser must send an HTTP GET request to the server. In this section I’ll follow the Page object through its life cycle phases to process this HTTP GET request. As Figure 21-2 shows, the current Page skips some of its life cycle phases when it is processing a non-postback request such as the first HTTP GET request. InitRecursive I’ll begin when the page enters its InitRecursive (or Init ) life cycle phase, where the ProcessRequest method invokes the InitRecursive method on the current Page (see Listing 21-1 and Figure 21-2 ). All server controls, including the Page , ScriptManager , and UpdatePanel , inherit the InitRecursive method from the Control base class. The InitRecursive method of a server control such as Page and UpdatePanel recursively invokes the InitRecursive methods of its child server controls. The InitRecursive method of a server control takes these actions: ❑ Sets the NamingContainer , ID (if it hasn’t already been set), and Page properties of its child server controls. This step does not apply to the ScriptManager because it does not contain any child server controls. However, it does apply to the UpdatePanel server controls on the current page because they do contain other server controls. ❑ Calls the ApplySkin to apply its associated skins if theming is enabled. This step does not apply to the ScriptManager because it does not render visual HTML, but it does apply to the UpdatePanel server controls because they may contain child server controls that use skins. ❑ Calls the OnInit method to raise its Init event and consequently invoke all the event handlers registered for this event. c21.indd 971c21.indd 971 8/20/07 8:37:04 PM8/20/07 8:37:04 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering 972 ❑ Calls the TrackViewState method to start tracking its view state. After the call into the TrackViewState method goes through, any changes made to the state of a server control, such as to its property values, will be marked as dirty and stored in the view state at the end of the current request and consequently sent to the client as part of the current page. As you can see, the bigger the view state the bigger the current page. The Init life cycle phase of the Page object is very complex in that it involves a lot of method calls on the Page , ScriptManager , PageRequestManager , and UpdatePanel classes. Because of this, it’s really easy to lose track of these method calls and their surrounding discussions. To make things a little easier on you, I’ll present these method calls in a diagram. At the end of each section I’ll update this diagram with the method calls discussed in the section. Therefore, by the time I’m done with our discussions of the Init life cycle phase of the Page object, you’ll have a single diagram that contains all the method calls in the order in which they’re made. I’ll do the same for other complex life cycle phases of the Page object. This way, for each complex life cycle phase you’ll have one diagram that contains all the method calls made in that phase in the order in which they’re made. Keep in mind that the vertical line in each diagram represents the timeline. The method calls positioned higher on these vertical lines occur earlier. Figure 21-3 presents the diagram that contains the method calls I’ve discussed so far. As you can see, when the Page enters its Init phase, it first invokes its own InitRecursive method. Since the Page calls this method on itself, the diagram uses an arrow that starts and ends with the vertical timeline associated with the page. The InitRecursive method then calls the InitRecusive methods of the ScriptManager and UpdatePanel before calling its own ApplySkin , OnInit , and TrackViewState methods. The InitRecursive methods of the ScriptManager and UpdatePanel , like the InitRecusive method of any other server control, call their own ApplySkin , OnInit , and TrackViewState methods. Now the question is: what happens when the OnInit methods of the ScriptManager and UpdatePanel server controls are invoked? In other words, what sequence of method calls do the calls into the OnInit methods of the ScriptManager and UpdatePanel server controls trigger? The dashed lines in Figure 21-3 are the placeholders for these missing method calls, which will be discussed in the following sections. The OnInit Method of ScriptManager Listing 21-2 presents the ScriptManager class’s internal implementation of the OnInit method, which it inherits from the Control base class. This implementation takes these steps. First, it calls the GetCurrent static method on the ScriptManager class to determine whether the current page already contains an instance of the ScriptManager server control. If so, it raises an exception because every page can contain only one instance of the ScriptManager server control. Next, the OnInit method adds the current instance of the ScriptManager server control to the Items collection of the current Page object. The next calls into the GetCurrent static method will return the instance stored in the Items collection of the current page. This ensures that the same instance will always be used for the entire lifespan of the current request. this.Page.Items[typeof(ScriptManager)] = this; c21.indd 972c21.indd 972 8/20/07 8:37:04 PM8/20/07 8:37:04 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering 973 This behavior of the Items collection has significant consequences when you’re enabling partial page rendering for a user control or a content page. Since a user control or a content page merges into its parent page and consequently forms a single page with its parent, you have to make sure that you do not declare separate instances of the ScriptManager server control in the parent page and the child page — be they user controls or content pages. You have two choices in these situations. You can declare the ScriptManager server control either in the parent or the child page (that is, user control or content page). Each option has its own pluses and minuses. If you declare the ScriptManager server control in the parent page, this automatically enables partial page rendering for all child pages — that is, for all user controls and content pages — which may not be the effect you’re looking for. Doing this also means that if you need to access the current ScriptManager server control from within your user control or content page, you must call the GetCurrent static method on the ScriptManager class to return a reference to the ScriptManager server control declared in the parent page. If you declare the ScriptManager in the child page you can directly access the current ScriptManager server control from the child page without using the GetCurrent static method. However, this also means that partial page rendering is only enabled for those user controls or content pages that directly contain the ScriptManager server control, which may not be the effect you’re looking for. Another side effect of this approach is that you cannot directly access the current Figure 21-3 InitRecursive Page UpdatePanel ScriptManager InitRecursive ( ) InitRecursive ( ) InitRecursive ( ) OnInit ( ) ApplySkins ( ) OnInit ( ) ApplySkins ( ) OnInit ( ) TrackViewState ( ) TrackViewState ( ) TrackViewState ( ) c21.indd 973c21.indd 973 8/20/07 8:37:04 PM8/20/07 8:37:04 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering 974 ScriptManager server control from your parent page because the parent page does not directly contain this server control. Instead you must use the GetCurrent static method to return a reference to this server control. Using this approach also means that if your parent page contains a partial-page- rendering-related functionality you must add code to check whether the child control does indeed contain an instance of the ScriptManager server control. If not, you must disable this functionality for this child control. OnInit then registers the OnPagePreRenderComplete method as an event handler for the PreRenderComplete event of the current Page object: this.Page.PreRenderComplete += new EventHandler(this.OnPagePreRenderComplete); Next, OnInit checks whether the page has been posted back to the server. If so, it calls the IsAsyncPostBackRequest static method on the current server-side PageRequestManager instance, passing in the request header collection to determine whether the page has been posted back asynchro- nously. (You’ll learn more about the server-side PageRequestManager class later.) As you’ll see, the ScriptManager server control delegates some of its responsibilities to this class, especially those respon- sibilities that handle asynchronous page postback or partial-rendering requests. The IsAsyncPostBackRequest static method will be thoroughly discussed later. For now, suffice it to say that this method uses the request headers to determine whether the page is posted back asynchronously — that is, whether the current request is an asynchronous partial-page-rendering request. Note that OnInit assigns the return value of this method to the _isInAsyncPostback Boolean field: if (this.Page.IsPostBack) this._isInAsyncPostBack = PageRequestManager.IsAsyncPostBackRequest(this.Page.Request.Headers); T h e ScriptManager exposes a read-only Boolean property named IsInAsyncPostBack that returns the value of the _isInAsyncPostBack field. Call this property on the current ScriptManager server control if you need to know whether the current request is an asynchronous page postback or partial-page-rendering request. Since the current Page object is processing the first HTTP GET request made to the server to visit the Web page for the first time, the IsAsyncPostBackRequest method of the current server-side PageRequestMananager instance is not invoked for this request. Next, OnInit calls the OnInit method on the current server-side PageRequestManager instance to initialize this instance. Unlike the ScriptManager , the PageRequestManager class is not a server control, which means that its OnInit method will not be automatically invoked by the containing page. That is why the OnInit method of the ScriptManager server control explicitly calls the OnInit method of the current server-side PageRequestManager instance: this.PageRequestManager.OnInit(); This is an example of a situation in which a server control such as ScriptManager has to work hand in hand with a non–server control object such as PageRequestManager throughout its life cycle. Thanks to the Page object, the server control’s life cycle methods, such as OnInit , are automatically called as the control goes through its life cycle phases. The same does not apply to the non–server control objects, such as PageRequestManager . In these cases, the server control’s life cycle methods, such as OnInit , must call the corresponding methods of the non–server control object to ensure that the c21.indd 974c21.indd 974 8/20/07 8:37:05 PM8/20/07 8:37:05 PM [...]... dashed line from the left in Figure 2 1-3 represents the method calls triggered by the call into the OnInit method of the current ScriptManager server control As you saw in this section, this call triggers a call into the OnInit method of the current server-side PageRequestManager instance Figure 2 1-4 extends Figure 2 1-3 to add this method call Note that Figure 2 1-4 still contains the first dashed line,... 2 1-4 represents the method calls triggered by the call into the OnInit method of the UpdatePanel server control As you saw in this section, these triggered method calls are the calls into the RegisterPanel and CreateContents methods of the UpdatePanel server 980 c21.indd 980 8/20/07 8:37:07 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering control Figure 2 1-5 extends Figure 2 1-4 ... RegisterUpdatePanel method of the current server-side PageRequestManager instance, which in turn triggers the call into the Add method of the _allUpdatePanels collection to add the UpdatePanel server control to this collection Figure 2 1-6 extends Figure 2 1-5 to add the latest triggered method calls Note that Figure 2 1-6 inherits the bottom dashed line from Figure 2 1-5 , and remember that this dashed line represents... ( ) ApplySkins ( ) OnInit ( ) TrackViewState ( ) Figure 2 1-4 977 c21.indd 977 8/20/07 8:37:06 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering Handling the Error Event As I mentioned earlier, errors that occur during the first request to a Web page enabled for partial page rendering are handled through normal ASP.NET error-handling practices (Complete coverage of these practices... returns a reference to the _triggers collection, as shown in Listing 2 1-1 2 Listing 2 1-1 2: The Triggers Collection Property of the UpdatePanel [DefaultValue((string)null), PersistenceMode(PersistenceMode.InnerProperty)] public UpdatePanelTriggerCollection Triggers { get { if (this._triggers == null) this._triggers = new UpdatePanelTriggerCollection(this); return this._triggers; } } As Listing 2 1-1 3 shows,... this collection Listing 2 1-7 : The RegisterUpdatePanel Method of the PageRequestManager internal void RegisterUpdatePanel(UpdatePanel updatePanel) { if (this._allUpdatePanels == null) this._allUpdatePanels = new List(); this._allUpdatePanels.Add(updatePanel); } Now let’s update Figure 2 1-5 with the latest method calls Recall that the top dashed line in Figure 2 1-5 represents the method... EventHandler(MyErrorHandler); } 978 c21.indd 978 8/20/07 8:37:06 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering Untitled Page As you can see from Listing 2 1-3 , the OnInit method of the current server-side PageRequestManager instance... Figure 2 1-6 with the latest method calls Recall that the dashed line in Figure 2 1-6 represents the method calls triggered by the call into the CreateContents method of the UpdatePanel, and that this method triggers the call into the CreateContentTemplateContainer and AddContentTemplateContainer methods of the UpdatePanel, as well as the InstantiateIn method of the ITemplate interface Figure 2 1-7 extends... method on the newly-created instance to return a reference to the Type object that represents the type of this instance: Type type = provider.GetType(); 990 c21.indd 990 8/20/07 8:37:10 PM Chapter 21: Page Life Cycle and Asynchronous Partial Page Rendering Next, it invokes the GetMethod on this Type object, passing in the value of the BuildTemplateMethodProviderMethod property to return a reference to the... Listing 2 1-6 , this method delegates the responsibility of registering the specified UpdatePanel control to the RegisterUpdatePanel method of the current server-side PageRequestManager instance Listing 2 1-6 : The RegisterUpdatePanel Method of ScriptManager void IScriptManagerInternal.RegisterUpdatePanel(UpdatePanel updatePanel) { this.PageRequestManager.RegisterUpdatePanel(updatePanel); } 983 c21.indd . defined in the ASP. NET AJAX server-side framework while the other is defined in the ASP. NET AJAX client-side framework. For ease of reference, I’ll refer to the one defined in the server-side framework. this and the next few chapters is to help you gain a solid understanding of the ASP. NET AJAX asynchronous page postback or partial-page-rendering-request-processing infra- structure. This infrastructure. order to understand the ASP. NET AJAX asynchronous page postback or partial-page-rendering-request- processing infrastructure and its constituent server-side and client-side components. As discussed

Ngày đăng: 09/08/2014, 06:23

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan