9.2. Making WebRequest Calls

The WebRequest class is the central object used for managing HTTP requests in ASP.NET AJAX. It provides a cross-browser compatible object for using the different underlying XMLHttpRequest implementations. Listing 9-3 (CallTimeWebRequest.aspx) is a Web page that does the equivalent of the request and response processing shown in Listing 9-2.

Example 9-3. CallTimeWebRequest.aspx
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Networking</title>
<script type="text/javascript">

var xmlhttp;

function pageLoad() {

var  Request = new Sys.Net.WebRequest();
    webRequest.set_url("Time.aspx");

    webRequest.add_completed(completedHandler);
    webRequest.invoke();
}

function completedHandler(result, eventArgs) {
    if(result.get_responseAvailable()) {
        alert(result.get_statusText());
        alert(result.get_responseData());
    }
}
</script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager runat="server" ID="ScriptManager1">
    </asp:ScriptManager>
    <div>
    </div>
    </form>
</body>
</html>

First, note that the code creates a Sys.Net.WebRequest object directly. You do not have to bother with checking the browser compatibility. You set the service address, add a completed callback function, and invoke the request. In the callback function, there is no need to check different integers against the status codes they represent. Instead, there is a check that the response is available, coupled with access to the data. This isn't dramatically different from what is done in Listing 9-2 when using the XMLHttpRequest object directly; however, it is more straightforward and avoids your having to look at each and every state change in the underlying object.

The WebRequest object provides abstractions for much of what is typically handled by the browser. Many of the interactions between browser and server can be controlled through the WebRequest object. The HTTP protocol defines a set of headers that you may want to control. You also may find that you don't want to accept the default behavior of waiting indefinitely for a server to respond once you have initiated a request.

9.2.1. Setting the HTTP Verb

HTTP requests include a verb for processing. Most of the time, you use either GET to query the server or POST to upload data. The HEAD verb is also used to gather information about the content type and to get caching information. The WebRequest object assumes a GET request unless you specify otherwise. A GET request passes values in the querystring, which many avoid from a security standpoint. Developers generally don't want their users to see the querystring, but in this case, the user doesn't see it since the request is being handled in code. A POST is more appropriate if you have a lot of data to send to the server. There are much smaller size limits for what is carried in the querystring than what can be sent in the body of a POST.

The WebRequest provides functions to retrieve and set the HTTP verb. In Debug mode, the class will check for a nonzero-length verb, but it has no way to verify that the verb is supported by the server, so any nonzero length value is accepted.

Listing 9-4 shows the EchoABC.aspx page that will receive and process a POST from the code in Listing 9-5. Note that it looks for a value by name in the request's form collection, since a POST doesn't transfer data in the querystring.

Example 9-4. EchoABC.aspx
<%@ Page Language="C#" %>
<script runat="server">
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    if(Request.Form["abc"] != null) {
        Response.Write(Server.HtmlEncode(Request.Form["abc"]));
    }
}
</script>

The page in Listing 9-5 (SetVerb.aspx) sets the HTTP verb to POST and sets the body to a name-value pair. The key is checked in the form collection from Listing 9-4, and its result is returned.

Example 9-5. SetVerb.aspx
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Networking</title>
<script type="text/javascript">
function pageLoad() {
    var webRequest = new Sys.Net.WebRequest();
    webRequest.set_url('EchoABC.aspx'),
    webRequest.set_httpVerb('POST'),
    webRequest.set_body('abc=123'),
    webRequest.add_completed(completedHandler);
    webRequest.invoke();
}

function completedHandler(result, eventArgs) {
    if(result.get_responseAvailable()) {
        alert(result.get_statusText());
        alert(result.get_responseData());
    }
}
</script>
</head>
<body>

<form id="form1" runat="server">
    <asp:ScriptManager runat="server" ID="ScriptManager1">
    </asp:ScriptManager>
    <div>
    </div>
    </form>
</body>
</html>

9.2.2. Establishing Timeout Limits

A call to set_timeout on the WebRequest can impose a limit on how long to you will wait for the response. The result can then be checked to find out if the call was terminated before reaching the limit. The get_timedOut property returns true if the call did not complete in time. To test your code you want to ensure that the limit is reached. You can do so by putting the thread to sleep for longer than the value of the set_timeout call.

System.Threading.Thread.Sleep(10000);

Listing 9-6 (Timeout.aspx) adds a call to set_timeout for five seconds and then discovers the timeout problem in the completion callback.

Example 9-6. Timeout.aspx
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Networking</title>
<script type="text/javascript">
function pageLoad() {
    var webRequest = new Sys.Net.WebRequest();
    webRequest.set_url('Sleep.aspx'),
    webRequest.set_httpVerb('POST'),
    webRequest.set_body('abc=123'),

    webRequest.set_timeout(5000);
    webRequest.add_completed(completedHandler);
    webRequest.invoke();
}

function completedHandler(result, eventArgs) {

    if(result.get_timedOut()) {
        alert('timed out'),
    }
    if(result.get_responseAvailable()) {

alert(result.get_statusText());
        alert(result.get_responseData());
    }
}
</script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager runat="server" ID="ScriptManager1">
    </asp:ScriptManager>
    <div>
    Making a WebRequest.
    </div>
    </form>
</body>
</html>

9.2.3. Adding Custom Headers

In addition to being able to detect timeouts, control the verb, and set the contents, you can send custom HTTP headers as part of the request. Listing 9-7 is the EchoHeaders.aspx page that simply echoes the HTTP headers that were included in a request. This server-side code creates a return page that shows exactly what is passed to it in the headers.

Example 9-7. EchoHeaders.aspx
<%@ Page Language="C#" %>
<script runat="server">
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    NameValueCollection headers = Request.Headers;
    foreach (string key in headers.Keys)
    {
        Response.Write(Server.HtmlEncode(key) +
            " = " +
            Server.HtmlEncode(headers[key]) +
            "<br />
");
    }
}
</script>

Requests to the page from Internet Explorer and Firefox are shown in Figure 9-1.

The headers sent by the different browsers are not the same. Internet Explorer provides the versions of the .NET Framework that it supports in the headers, while Firefox does not. Both browsers accept gzip and deflate for encodings. The language header differs based on the selections made in the different browsers. I don't speak Japanese, but I have it in my list of preferred languages of both browsers for testing localization features.

Figure 9-1. Figure 9-1

Listing 9-8 (CustomHeaders.aspx) makes a call to the EchoHeaders.aspx page, while adding a few unique headers to the request.

Example 9-8. CustomHeaders.aspx
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Networking</title>
<script type="text/javascript">
function pageLoad() {
    var webRequest = new Sys.Net.WebRequest();
    webRequest.set_url('EchoHeaders.aspx'),

    webRequest.get_headers()["Preferred-Publisher"] = "Wrox";
    webRequest.get_headers()["Preferred-Album"] = "Rift";

webRequest.get_headers()["UA-CPU"] = "Altair MIPS";
    webRequest.add_completed(completedHandler);
    webRequest.invoke();
}

function completedHandler(result, eventArgs) {
    if(result.get_responseAvailable()) {
        $get("placeholder").innerHTML = result.get_responseData();
    }
}
</script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager runat="server" ID="ScriptManager1">
    </asp:ScriptManager>
    <div id="placeholder">
    </div>
    </form>
</body>
</html>

The same requests with some additional headers from Internet Explorer and Firefox now show different results than the previous request. The Preferred-Publisher and Preferred-Album headers are now reported as part of the request. Although the preferred-publisher and preferred-album are displayed, in the test with IE, the UA-CPU header is the same as it was before the request that tried to modify it. This is because IE set this header after the page set its value, since this is a standard header that IE always sets itself. The WebRequest object allows you to add headers, but the browser itself still has the last say about what is actually transmitted to the server. Figure 9-2 shows the result of an additional set of requests from Internet Explorer and Firefox with the requests that include new additional headers.

9.2.4. Passing Extra Data

The WebRequest class automatically passes data from the caller to the completion event handler function. Many times, you want the callback code to benefit from having more data than is typically provided in default operations. The ASP.NET AJAX userContext parameter provides a way to pass data from the caller to the callback without even sending it to the server, and this tells the event handler some extra context information about why or where the call was made. The framework manages this extra information and includes it as part of the callback parameters automatically, so it looks as though this information came from the server. Listing 9-9 (UserContext.aspx) is a page that adds userContext data to the call to the EchoHeaders.aspx page.

Example 9-9. UserContext.aspx
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Networking</title>

<script type="text/javascript">
function pageLoad() {
    var webRequest = new Sys.Net.WebRequest();
    webRequest.set_url('EchoHeaders.aspx'),

    webRequest.set_userContext('send this data to the callback'),
    webRequest.add_completed(completedHandler);
    webRequest.invoke();
}

function completedHandler(result, eventArgs) {
    if(result.get_responseAvailable()) {

        var userContext = result.get_webRequest().get_userContext();
        $get('placeholder').innerHTML = userContext;
    }
}
</script>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager runat="server" ID="ScriptManager1">
    </asp:ScriptManager>
    <div id="placeholder" >
    </div>
    </form>
</body>
</html>

Figure 9-2. Figure 9-2

The WebRequest does not include the user context information in what is sent to the server. Instead, the data is stored locally and then made available during the callback. You can store complex JavaScript types without needing to worry about how they will be serialized for including in an HTTP request. This also keeps the request/response payload lighter.

9.2.4.1. Resolving the Full URL

In Web development, it is often useful to make decisions based on what part of an application the user is accessing. The WebRequest provides a method for retrieving the full URL of a request that is about to be made. When setting up the request, you can specify a complete address for the URL or a relative path. The getResolvedUrl function always yields the full path regardless of which form you provide:

alert(webRequest.getResolvedUrl());

It's important to note that you should not drive security decisions based on the resolved URL in JavaScript running in the browser. The base URL can be spoofed through script running in the JavaScript console. It's safe to assume that any JavaScript in your page might be modified by some kind of Trojan program or unauthorized process on the user's machine, so you must take care in how much trust you place in that code. You should rely on server-side validation of every aspect in the client/server interaction in cases where you have security concerns.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset