/China/msdn/library/web services/ASP . net/us 050 1 cutting edge . mspx? Manufacturer = true
Basic knowledge of controlling script callback
ASP.NET script callback mechanism consists of two key elements: server-side code that responds to user operations, and JavaScript callback code that handles the results generated by server-side events at the client. As far as the page callback itself is concerned, as I mentioned in the last article, you can attach some script code generated by ASP.NET to the page button, which performs a postback invisible to the user. Because the target of the request is the current page, the page will be published to itself, which is similar to its behavior in a normal postback event, except that the life cycle of the page is shortened. The page must implement the ICallbackEventHandler interface so that methods with predefined signatures can be called to generate results for the client.
So, what's the difference between this scheme when the control triggers an out-of-band call? In this case, the target URL of the "invisible" postback is the URL of the page hosting the caller control. The control must implement ICallbackEventHandler to provide a way to generate some results for the client. Similarly, the control is responsible for inserting any JavaScript code needed to process the results and refresh the page in the host page.
A control with a callback function is just a control that implements the interfaces of ICallbackContainer and ICallbackEventHandler, and each interface has a method. The ICallbackContainer interface has a method that can return the script code that triggers the remote call; The ICallbackEventHandler interface provides server-side code that is executed during the call. ICallbackEventHandler is also an interface that pages with callback functions must implement. The following code shows the declaration of a sample custom control that implements the callback interface:
Public class CallbackValidator: WebControl,
INamingContainer,ICallbackContainer,ICallbackEventHandler
In the implementation of the ICallbackContainer interface, you may need to call the GetCallbackEventReference method of this page to get the correct JavaScript call that can start the server event. I'll talk about these later.
Return to the peak
Callback validator control
To understand a server control with a callback function, let's look at an example of a custom validator control with a ASP.NET script callback function. In ASP.NET, validation controls are used to check and validate the input of form fields defined in web pages. The validator is a server control that inherits from the BaseValidator class, which in turn inherits from the Label.
Each validation control references an input control located elsewhere on the page. When the page is submitted, the content of any monitored server control is passed to the validator for further processing. Each validator performs a different type of validation. For example, the CompareValidator control uses comparison operators (such as less than, equal to, or greater than) to compare user input with a fixed value. RangeValidator ensures that the user input is within the specified range, while RegularExpressionValidator only validates the user input when it matches the pattern defined by the regular expression.
Typically, authentication takes place on the server. However, ASP.NET also provides a complete client-side implementation for most validation controls, and allows users to write custom client-side scripts for the remaining validation controls. This makes browsers that support DHTML (such as Microsoft? Internet Explorer 4.0 and later) can perform authentication on the client immediately after the user clicks or clicks a location outside the monitored input domain. In many cases, client-side verification is powerful enough to detect many major errors and notify users. For example, the RequiredFieldValidator control can verify that a given field cannot be empty. You can verify the current value without sending it back to the server.
If client-side validation is turned on, the page will not post back until all input fields contain valid data. In order to run security code and prevent malicious and secret attacks, you should still verify the data on the server; Server-side validation is always performed by validator controls, even client-side validation. In addition, not all types of verification can be done at the client. In fact, if you need to verify the database, you have no choice but to send it back to the server. This is the problem.
A regular postback involves the entire page. Upload the entire view state, process the entire page, and generate, download and present the same big response. Wouldn't it be nice if you could send an optimized out-of-band request to the server and only check the status of the verified control?
In ASP.NET, there is no such control. Then let's write such a control. I will name it CallbackValidator. CallbackValidator is a custom ASP.NET 2.0 control. The purpose of generating this control is to demonstrate how the control makes out-of-band calls to the home page and how to handle events on the server itself.
When I started this project, I didn't have an ambitious goal: my initial goal was only to modify the CustomValidator standard control. For this record, the CustomValidator control uses programmatically defined validation logic to check the validity of user input. You should use this method if you don't know the value to check in advance. The original intention of the CallbackValidator control is to provide a way to perform server-side validation without posting back the entire page. I realized that without much extra effort, I can have a control similar to a custom button, which can verify many input fields on the server without posting back the whole page. At this time, my revision work has been half finished. This behavior is all about the CallbackValidator control.
Before I go into the essence of this control, let's take a look at the figure 1 The Submit button on this page will only publish all values to the server in the normal way. In fact, these values will be processed on the client side, and if all these values need to be passed, the control will pass them to the server, where all control inputs will be verified using the server-side verification code (if any). The Validate button triggers an out-of-band call to the Web server and only validates the specified input control. When it returns, you will know which values passed the server's verification. For example, in figure 1, you will know whether the user ID has been adopted before attempting to submit the remaining data.
Figure 1 Input Form with Callback Function Verification
Figure 2 shows the source code of this page. As you can see, it contains an HTML server form, some text boxes (each bound to a standard validation control) and an instance of a custom CallbackValidator control. This control is actually responsible for creating and displaying the Validate button.
Return to the peak
How does this control work?
CallbackValidator control inherits from WebControl and implements the INamingContainer interface. In addition, it also implements the interfaces of ICallbackContainer and ICallbackEventHandler for callback support.
The ICallbackContainer interface requires the GetCallbackScript method to be declared as follows:
String getcallbackscript (ibutton controlbuttoncontrol, string parameter)
GetCallbackScript has two parameters. The first is a reference to the page control that is expected to trigger the callback. The second parameter (string) represents any context that the caller wants to pass to the method to help build the output. As can be seen from the name, the GetCallbackScript method uses JavaScript function calls to prepare and return a string to be attached to the specified button control to trigger a remote call.
This button control parameter enables you to specify exactly which button in the control UI you want to make a JavaScript call to. The sample CallbackValidator control has only one clickable button; On the other hand, the GridView control has many clickable buttons, each of which is used for page navigation or link buttons in the title. In ASP.NET 2.0, all the controls that play the role of buttons in the form need to implement a new interface-iButton control. This interface is illustrated in detail in Figure 3. It is implemented by the following Web controls: Button, LinkButton and ImageButton. HTML button controls cannot implement this interface. Please note that in Microsoft. NET Framework 1.x, IButtonControl interface is only for Windows? Form button controls exist (although the collection of members is completely different).
The second interface that controls with callback functions need is iCallBackEventHandler-this interface is also needed by pages that support script callbacks. The interface consists of a method:
string RaiseCallbackEvent(string event argument)
This method receives an input value in the form of a string, performs some server-side work, and then returns a response in the form of a string. It is very important here that both input and output data can be packaged into strings for transmission; The actual content and format of the string are determined by the encoder.
Before I discuss the implementation of the CallbackValidator control, let's take a look at Figure 4, which shows how the control adapts to the HTTP handler in the page that handles ASPX resource requests. The CallbackValidator control looks like a button with some script code attached. Script code is the content returned by its GetCallbackScript method. When the button (Validate) is clicked, it will trigger a background postback to send the view state, the current input value and two custom strings named CALLBACKPARAM and CALLBACKID. The former contains the input value when creating RaiseCallbackEvent in the GetCallbackScript method body, and the CALLBACKID is responsible for identifying the server-side object that handles the server event. Once the page HTTP handler that extracts the request from the ASP.NET runtime is behind the server, it will try to find the control with that ID and implement ICallbackEventHandler. If successful, the RaiseCallbackEvent method of the control will be called and its output will be returned to the client. If the target of CALLBACKID is a page, the HTTP handler will check whether the page implements an interface, and then continue in the usual way.
Return to the peak
Construction control
CallbackValidator is a composite control whose user interface consists of a simple button. You can easily extend this aspect of the control by adding some properties to set the style of the button (link, press, image or anything else). The text displayed on the button is set by the ButtonText property. The collection property named ControlsToValidate collects the IDs of all page validators to be tested on the server during callback. This property is implemented as a StringCollection type, which starts with null. The code in Figure 5 only allows you to add a control ID at run time, which is usually done in the Page_Load event:
Void Page_Load (object sender, EventArgs e) {
Callback validator 1. ControlsToValidate . Add(" valUserId ");
Callback validator 1. ControlsToValidate . Add(" valEmail ");
}
Note that this collection class does not maintain its view state content. Therefore, you must always reinitialize incoming requests. Also note that validation controls should be added to the collection, not input controls. During the remote call, the CallbackValidator control calls the Validate method of the associated control and stores the response of the client callback. CallbackValidator controls work with existing validators, so they can all be tested through out-of-band calls; It is actually not a new type of validator.
As shown in figure 5, the CallbackValidator control creates a button control and attaches some code to its OnClientClick property. OnClientClick is a new property introduced in ASP.NET 2.0, which is used to add JavaScript calls to HTML onclick events. In ASP.NET 2.0, the following two lines of code have exactly the same function:
Button. attributes[" onclick "]= js; //ASP.NET 1 . x; Still valid in 2.0.
Button. OnClientClick = js//ASP.NET 2.0
The code associated with the validation button is obtained through a specific method wrapped in the ICallbackContainer interface. Note that starting with Beta 1, you don't need to use the ICallbackContainer interface, but it helps keep the code simple. In last month's example, I didn't use this interface, and I didn't even mention it in the MSDN Beta 1 document that discussed script callbacks. However, ASP.NET controls (mainly GridView) that benefit from script callbacks will implement this interface. The only component that uses the ICallbackContainer interface is the control itself, which means that you can easily write a control with a callback function without using the interface.
The JavaScript function call returned by GetCallbackScript comes from the following statement:
Page. GetCallbackEventReference(
this,args," CallbackValidator_UpdateUI "," null "));
The first parameter (this) represents the current control, which sets the CALLBACKID field in the issued request. The second parameter (args) is the input string of the server-side RaiseCallbackEvent method. The third parameter is the name of the JavaScript callback function, which is used to process the output of the RaiseCallbackEvent method. Finally, the fourth parameter is empty here, which represents the JavaScript object passed as the callback function context.
CallbackValidator control must ensure that JavaScript callbacks are defined in the host page, and must determine the format and content of args parameters. The RaiseCallbackEvent implementation only needs one type of information from its client caller: the list of validators to test. The following code concatenates all validator IDs into a string separated by vertical bars:
int I = 0;
StringBuilder sb = new StringBuilder(" ");
Foreach (string s in controls validate)
{
If (i>0) someone adds ("|");
Someone (short for someone) added;
i++;
}
String parameter = string. Format ("{0}"), sb. ToString());
The JavaScript code example bound to the Validate button in Figure 2 may look like the following code:
WebForm_DoCallback(
CTL 00 $ page body $ callback validator 1 ',
valUserId|valEmail ',
Callback Validator_UpdateUI,
Empty,
null);
Note that the ID of the CallbackValidator control is generated by the server so that each control on the page can be uniquely identified.
Return to the peak
Solve national problems
As shown in Figure 4, the postback request contains some input fields. In addition to the CALLBACKID and CALLBACKPARAM fields mentioned above, the request also contains some other input fields. More precisely, it contains all the input fields in the form and two input fields specific to the callback operation. In other words, the view state is sent back with the current values of these input fields (text boxes, drop-down lists, etc.). ).
Before checking the callback status of the request and finding out which object (page or control) wants to call RaiseCallbackEvent, the HTTP page handler will restore the view state and published values. Based on this, you may guess that the code defined in the RaiseCallbackEvent method will be executed in a consistent and updated state. In particular, you might guess that all validators called by the RaiseCallbackEvent method of the CallbackValidator control will test the current value of the input control to which they are bound. However, as can be seen from the title of this section, this is not the case. Take a look at the RaiseCallbackEvent code in Figure 6.
This method retrieves the validator control and calls its Validate method. The method performs its task (depending on the type of validator) and sets the IsValid property to True (valid) or False (invalid). Next, the RaiseCallbackEvent method builds its response to the client page. The return string is a collection of strings separated by vertical lines, and the format of each string is as follows:
ControlID: valid (0/ 1): Message: Tooltip
The first tag is the client ID of the control, which is a fully qualified ID and will be considered for creation due to the master page and the naming container. The second tag is 0 or 1, depending on the value of IsValid. The third is marked as a message that the validator displays after a full postback. This corresponds to the Text (default) or ErrorMessage property of the validator. If both properties are empty, I also forced a * string. According to the design, the text should contain some text that only marks the field as invalid, and ErrorMessage provides a more detailed description of the error. If the ShowDetailedInfo property of CallbackValidator is true, I will use the ErrorMessage string as a tooltip, as shown in Figure 7.
Figure 7 Validation Error Message
So, where is the discussion related to state? This mechanism is feasible in theory, but it is different when it comes to practical value. When debugging, I realized that the results of the verification test were completely unreliable. For example, the User ID text box is designed to accept anything except "Dino" and an empty string. However, it only applies to regular callbacks, not to situations where callback verification is used. Some appropriately placed breakpoints show that all text boxes retain their original values and ignore what they typed before trying to verify. This problem has nothing to do with the view state, but with the published value. The page mechanism works normally as usual; I just can't receive the value I think is correct from the client.
If you browse the HTML source code of the page that uses ASP.NET callback, you will find that a JavaScript function named WebForm_InitCallback was called when the page was loaded. This function is part of ASP.NET 2.0 infrastructure, and it is inserted into the page through WebResource.axd system handler. See if the source code of this function works well. For details on how to get this code, please refer to last month's column. Basically, WebForm_InitCallback builds the body of the POST request when the page loads. The main body of the page is a string (its name is __theFormPostData), which is filled with the contents of the view state and all the input fields in the form. The code is correct; But the execution time is not what I expected! The contents of these input fields are collected when loading, but will not be updated with the values provided by the user when posting back. This is why the server state looks incorrect. To solve this problem, I just repeated the call to WebForm_InitCallback before starting the out-of-band call (see Figure 6). Please note that this is actually an expected behavior, not an error. The discussion about the system calling WebForm_InitCallback before out-of-band calling is for the case that the user wants to perform the callback in the context of the data originally sent from the server.
Return to the peak
JavaScript file as embedded resource
At the end of this column, I will discuss a very useful technology that greatly simplifies JavaScript code insertion in ASP.NET 2.0 custom controls. This technology can also be used in ASP.NET1.x, and the idea is simple: write your JavaScript code in a regular JS file and add it to the project as an embedded resource. (in Visual Studio? NET properties window). In addition, add the namespace of the component before the resource name. Next, when you need to use scripts in your code, please perform the operations performed by the EmbedScriptCode method in Figure 6. With a little skill, you can gain a lot in code maintenance and readability.
Return to the peak
summary
ASP.NET script callback is a very powerful function, which can save the time of updating each page. Despite the server request, the entire page remains unchanged in the browser window. Its advantages are twofold. First, users don't think it is necessary to reply, and will continue to read or use the page. Second, only some parts of the page will be refreshed (using the HTML object model). In the columns of 12 in August 2004 and February 2004, I have discussed this basic function in depth. This month, I discussed how to implement callbacks in custom controls to provide greater flexibility in the controls you build.