Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 62 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
62
Dung lượng
391,35 KB
Nội dung
Consuming Web Services Via JSON Messages As you saw in the previous chapter, you can use the XMLHttpExecutor , WebRequestManager , and WebRequest classes to make requests to the server. However, this approach requires you to write lot of code to make a request. The ASP.NET AJAX client-side framework includes a class named WebServiceProxy that encapsulates all the logic that uses the XMLHttpExecutor , WebRequestManager , and WebRequest classes to make a request to the server. This enables you to make a request with minimal time and effort. The downside of the WebServiceProxy approach is that it supports only JSON messages. If you need to use normal SOAP messages to communicate with a Web service, you have to use the techniques discussed in the previous chapter. This chapter begins by discussing the important members of the WebServiceProxy class. WebServiceProxy As you can see in Listing 14-1 , the constructor of the WebServiceProxy class doesn’t do anything. Listing 14-1: The Constructor of the WebServiceProxy Class Sys.Net.WebServiceProxy = function Sys$Net$WebServiceProxy() { } Sys.Net.WebServiceProxy.registerClass(‘Sys.Net.WebServiceProxy’); Timeout The WebServiceProxy class exposes a getter named get_timeout and a setter named set_timeout that enable you to get and set the request timeout, as shown in Listing 14-2 . c14.indd 535c14.indd 535 8/20/07 6:13:45 PM8/20/07 6:13:45 PM Chapter 14: Consuming Web Services Via JSON Messages 536 Listing 14-2: Getting and Setting the Request Timeout function Sys$Net$WebServiceProxy$set_timeout(value) { this._timeout = value; } function Sys$Net$WebServiceProxy$get_timeout() { return this._timeout; } Default Succeeded Callback You call the set_defaultSucceededCallback method on the WebServiceProxy object to specify a JavaScript function as the default succeeded callback for Web requests (see Listing 14-3 ). As the name implies, this JavaScript function is automatically invoked when a request is completed successfully. You call the get_defaultSucceededCallback method on the WebServiceProxy object to return a refer- ence to the JavaScript function registered as the default succeeded callback (see Listing 14-3 ). Listing 14-3: Getting and Setting the Default Succeeded Callback function Sys$Net$WebServiceProxy$set_defaultSucceededCallback(value) { this._succeeded = value; } function Sys$Net$WebServiceProxy$get_defaultSucceededCallback() { return this._succeeded; } Default Failed Callback You can call the set_ defaultFailedCallback method on the WebServiceProxy object to specify a JavaScript function as the default failed callback for Web requests (see Listing 14-4 ). As the name suggests, this JavaScript function is automatically invoked when a request fails. Call the get_defaultFailedCallback method on the WebServiceProxy object to return a reference to the JavaScript function registered as the default failed callback (see Listing 14-4 ). Listing 14-4: Getting and Setting the Default Failed Callback function Sys$Net$WebServiceProxy$set_defaultFailedCallback(value) { this._failed = value; } function Sys$Net$WebServiceProxy$get_defaultFailedCallback() { return this._failed; } c14.indd 536c14.indd 536 8/20/07 6:13:46 PM8/20/07 6:13:46 PM Chapter 14: Consuming Web Services Via JSON Messages 537 Path Call the set_path method on the WebServiceProxy object to specify a URL as the target URL for Web requests (see Listing 14-5 ). Call the get_path method on the WebServiceProxy object to return the target URL (see Listing 14-5 ). Listing 14-5: Getting and Setting the Path function Sys$Net$WebServiceProxy$set_path(value) { this._path = value; } function Sys$Net$WebServiceProxy$get_path() { return this._path; } Invoking a Web Method Invoking a Web method is at the heart of the WebServiceProxy class. The main responsibility of the _invoke method is to invoke the Web method with a specified name and parameter names and values that belong to a Web service with a specified URL. As you can see in Listing 14-6 , the _invoke method takes the following parameters: ❑ servicePath : This parameter specifies the target URL for the Web service. For example, if you have a Web service named Service.asmx running locally on your machine, its service path is as follows: http://localhost/Service.asmx ❑ methodName : This parameter is a string that contains the name of the Web method being invoked. ❑ useGet : This parameter is a Boolean value that specifies whether the request must be made using the GET HTTP verb. ❑ params : This parameter is a dictionary that contains the names and values of the parameters of the Web method being invoked. ❑ onSuccess : This optional parameter references a JavaScript function that will be called when the request completes successfully. ❑ onFailure : This optional parameter references a JavaScript function that will be called when the request fails. ❑ userContext : This optional parameter references a JavaScript object that will be passed into the JavaScript functions referenced by the onSuccess and onFailure parameters when they’re invoked. This enables you to pass arbitrary information into the _invoke method for retrieval when these JavaScript functions are called. The type of this information depends on the specifics of your application. The WebServiceProxy class does not do anything with the user context. It simply keeps it somewhere and passes it into the JavaScript functions referenced by the onSuccess and onFailure parameters when they’re invoked. c14.indd 537c14.indd 537 8/20/07 6:13:46 PM8/20/07 6:13:46 PM Chapter 14: Consuming Web Services Via JSON Messages 538 Listing 14-6: The _invoke Method function Sys$Net$WebServiceProxy$_invoke(servicePath, methodName, useGet, params, onSuccess, onFailure, userContext) { if (onSuccess === null || typeof onSuccess === ‘undefined’) onSuccess = this.get_defaultSucceededCallback(); if (onFailure === null || typeof onFailure === ‘undefined’) onFailure = this.get_defaultFailedCallback(); if (userContext === null || typeof userContext === ‘undefined’) userContext = this.get_defaultUserContext(); return Sys.Net.WebServiceProxy.invoke(servicePath, methodName, useGet, params, onSuccess, onFailure, userContext, this.get_timeout()); } Note that the _invoke method returns a reference to the WebRequest object that represents the request made to the Web service. Now, let’s walk through the implementation of the _invoke method. If no JavaScript function has been assigned to the onSuccess parameter as a succeeded callback, the _invoke method calls the get_defaultSucceededCallback method to return and use the JavaScript function registered as the default succeeded callback: if (onSuccess === null || typeof onSuccess === ‘undefined’) onSuccess = this.get_defaultSucceededCallback(); If no JavaScript function has been assigned to the onFailure parameter as a failed callback, the _invoke method calls the get_defaultFailedCallback method to return and use the JavaScript function registered as the default failed callback: if (onFailure === null || typeof onFailure === ‘undefined’) onFailure = this.get_defaultFailedCallback(); If no JavaScript object has been assigned to the userContext parameter, the _invoke method calls the get_defaultUserContext method to return and use the JavaScript object registered as the default user context: if (userContext === null || typeof userContext === ‘undefined’) userContext = this.get_defaultUserContext(); Finally, the _invoke method delegates the responsibility of invoking the Web method with a specified name and parameter names and values to the invoke static method of the WebServiceProxy class: return Sys.Net.WebServiceProxy.invoke(servicePath, methodName, useGet, params, onSuccess, onFailure, userContext, this.get_timeout()); Note that the _invoke method passes the return value of the get_timeout method as the last parameter into the invoke method. This return value specifies the request timeout. c14.indd 538c14.indd 538 8/20/07 6:13:47 PM8/20/07 6:13:47 PM Chapter 14: Consuming Web Services Via JSON Messages 539 invoke Listing 14-7 presents the internal implementation of the WebServiceProxy class’s invoke static method. Listing 14-7: The invoke Static Method of the WebServiceProxy Class Sys.Net.WebServiceProxy.invoke = function Sys$Net$WebServiceProxy$invoke(servicePath, methodName, useGet, params, onSuccess, onFailure, userContext, timeout) { var request = new Sys.Net.WebRequest(); request.get_headers()[‘Content-Type’] = ‘application/json; charset=utf-8’; if (!params) params = {}; var urlParams = params; if (!useGet || !urlParams) urlParams = {}; request.set_url(Sys.Net.WebRequest._createUrl(servicePath+”/”+methodName, urlParams)); var body = null; if (!useGet) { body = Sys.Serialization.JavaScriptSerializer.serialize(params); if (body === “{}”) body = “”; } request.set_body(body); request.add_completed(onComplete); if (timeout && timeout > 0) request.set_timeout(timeout); request.invoke(); function onComplete(response, eventArgs) { if (response.get_responseAvailable()) { var statusCode = response.get_statusCode(); var result = null; try { var contentType = response.getResponseHeader(“Content-Type”); if (contentType.startsWith(“application/json”)) result = response.get_object(); else if (contentType.startsWith(“text/xml”)) result = response.get_xml(); else result = response.get_responseData(); } (continued) c14.indd 539c14.indd 539 8/20/07 6:13:47 PM8/20/07 6:13:47 PM Chapter 14: Consuming Web Services Via JSON Messages 540 Listing 14-7 (continued) catch (ex) { } var error = response.getResponseHeader(“jsonerror”); var errorObj = (error === “true”); if (errorObj) result = new Sys.Net.WebServiceError(false, result.Message, result.StackTrace, result.ExceptionType); if (((statusCode < 200) || (statusCode >= 300)) || errorObj) { if (onFailure) { if (!result || !errorObj) result = new Sys.Net.WebServiceError(false /*timedout*/, String.format(Sys.Res.webServiceFailedNoMsg, methodName), “”, “”); result._statusCode = statusCode; onFailure(result, userContext, methodName); } else { var error; if (result && errorObj) error = result.get_exceptionType() + “ “ + result.get_message(); else error = response.get_responseData(); alert(String.format(Sys.Res.webServiceFailed, methodName, error)); } } else if (onSuccess) onSuccess(result, userContext, methodName); } else { var msg; if (response.get_timedOut()) msg = String.format(Sys.Res.webServiceTimedOut, methodName); else msg = String.format(Sys.Res.webServiceFailedNoMsg, methodName) if (onFailure) onFailure( new Sys.Net.WebServiceError(response.get_timedOut(), msg, “”, “”), userContext, methodName); c14.indd 540c14.indd 540 8/20/07 6:13:47 PM8/20/07 6:13:47 PM Chapter 14: Consuming Web Services Via JSON Messages 541 else alert(msg); } } return request; } This method first instantiates a WebRequest object to represent the current Web request: var request = new Sys.Net.WebRequest(); Next, it calls the get_headers method to return a reference to the dictionary that contains the names and values of the request headers, and assigns the string ‘application/json; charset=utf-8’ as the value of the Content-Type request header: request.get_headers()[‘Content-Type’] = ‘application/json; charset=utf-8’; This value instructs the server that the body of the message contains a JSON object. As you’ll see later, the server-side code uses a serializer to deserialize a .NET object from this JSON representation. Next, it checks whether at least one of the following conditions are met: ❑ You’re making a GET HTTP request to the server. As previously discussed, the third parameter passed into the invoke method is a Boolean that specifies whether the GET HTTP verb must be used. ❑ The Web method being invoked does not take any arguments. If at least one of these conditions is met, the invoke method passes the dictionary that contains the names and values of the arguments of the Web method being invoked as the second argument to a method named _createUrl . If neither of the conditions is met, the invoke method passes an empty dictionary as the second argument. The main responsibility of the _createUrl method is to create a URL that consists of the following two main parts: ❑ The URL part, which itself consists of two parts separated by the forward slash character ( / ), where the first part contains the service path (the target URL) of the Web service, and the second part contains the name of the Web method being invoked. As you can see in the following code excerpt from Listing 14-7 , the Web method name is passed to the server as part of the URL. ❑ The query string part, which consists of query string parameters and their associated values, where each parameter and its associated value respectively contain the name and value of an argument of the Web method being invoked. As you can see in the following code excerpt from Listing 14-7 , the names and values of the arguments of the Web method are passed to the server as a query string if at least one of the previously mentioned conditions is met. c14.indd 541c14.indd 541 8/20/07 6:13:48 PM8/20/07 6:13:48 PM Chapter 14: Consuming Web Services Via JSON Messages 542 var urlParams = params; if (!useGet || !urlParams) urlParams = {}; var url = Sys.Net.WebRequest._createUrl(servicePath+”/”+methodName, urlParams); Next, the invoke static method calls the set_url getter on the WebRequest object that represents the current request to specify the URL returned from the _createUrl method as the target URL of the request: request.set_url(url); Then, the invoke method checks the value of its third parameter to determine whether it must make a POST HTTP request to the server. If so, it invokes a static method named serialize on an ASP.NET AJAX class named JavaScriptSerializer , passing in the dictionary that contains the names and values of the arguments of the Web method being invoked to serialize this dictionary into a JSON object. It assigns this JSON object to a local variable named body , which contains the body of the POST HTTP request being made to the server. var body = null; if (!useGet) { body = Sys.Serialization.JavaScriptSerializer.serialize(params); if (body === “{}”) body = “”; } Next, the invoke static method calls the set_body method on the WebRequest object that represents the current request, passing in the body local variable to set the body of the request: request.set_body(body); If the request is a GET HTTP request, the body is null . If the request is a POST HTTP request, the body contains the JSON representation of the names and values of the parameters of the Web method being invoked. In other words, the names and values of the parameters are passed as part of query string if the request is a GET HTTP request, and as part of the body of the request if the request is a POST HTTP request. Next, the invoke static method calls the add_completed method on the WebRequest object that represents the current GET or POST HTTP request, to register a private JavaScript function named onComplete as an event handler for the completed event of the WebRequest object: request.add_completed(onComplete); This object raises its completed event when the request finally completes. The onComplete function is private to the invoke static method and cannot be accessed from outside this method (discussed in more detail later in this chapter). Next, the invoke static method calls the set_timeout method on the WebRequest object that represents the current GET or POST HTTP request to set the request timeout: c14.indd 542c14.indd 542 8/20/07 6:13:48 PM8/20/07 6:13:48 PM Chapter 14: Consuming Web Services Via JSON Messages 543 if (timeout && timeout > 0) request.set_timeout(timeout); Finally, it calls the invoke method on the WebRequest object to make the request to the Web service: request.invoke(); _createUrl As Listing 14-8 shows the _createUrl static method of the WebRequest class takes the following two parameters: ❑ url : This parameter is a string that contains the target URL. ❑ queryString : This parameter is a dictionary that contains the names and values of parameters being sent to the server as a query string. For example, in the case of Listing 14-7 , these parame- ters are the parameters of the Web method being invoked. Listing 14-8 : The _createUrl Static Method of the WebRequest Class Sys.Net.WebRequest._createUrl = function Sys$Net$WebRequest$_createUrl(url, queryString) { if (!queryString) return url; var qs = Sys.Net.WebRequest._createQueryString(queryString); if (qs.length > 0) { var sep = ‘?’; if (url && url.indexOf(‘?’) !== -1) sep = ‘&’; return url + sep + qs; } else return url; } The _createUrl static method first calls the _createQueryString static method on the WebRequest class, passing in the dictionary that contains the names and values of the parameters being sent to the server as a query string: var qs = Sys.Net.WebRequest._createQueryString(queryString); As you’ll see shortly, this static method builds and returns a valid query string out of the items in this dictionary. Next, the _createUrl method checks whether the URL contains the required ? separator character, which separates a query string from its associated URL. If it does not contain this character, the _createUrl method adds it between the URL and the query string: c14.indd 543c14.indd 543 8/20/07 6:13:48 PM8/20/07 6:13:48 PM Chapter 14: Consuming Web Services Via JSON Messages 544 var sep = ‘?’; if (url && url.indexOf(‘?’) !== -1) sep = ‘&’; return url + sep + qs; _createQueryString Listing 14-9 presents the internal implementation of the WebRequest class’s _createQueryString static method. As you can see, this method takes the following two parameters: ❑ queryString : This parameter references a dictionary that contains the names and values of the parameters to be embedded in the query string. In the case of Listing 14-7 , this dictionary contains the names and values of the parameters of the Web method being invoked. ❑ encodeMethod : This parameter references a JavaScript function that takes a string as its parameter and encodes certain characters in the string. Listing 14-9 : The _createQueryString Method of the WebRequest Class Sys.Net.WebRequest._createQueryString = function Sys$Net$WebRequest$_createQueryString(queryString, encodeMethod) { if (!encodeMethod) encodeMethod = encodeURIComponent; var sb = new Sys.StringBuilder(); var i = 0; for (var arg in queryString) { var obj = queryString[arg]; if (typeof(obj) === “function”) continue; var val = Sys.Serialization.JavaScriptSerializer.serialize(obj); if (i !== 0) sb.append(‘&’); sb.append(arg); sb.append(‘=’); sb.append(encodeMethod(val)); i++; } return sb.toString(); } The _createQueryString method first checks whether the caller has specified a value for the encodeMethod parameter. If not, it uses the JavaScript encodeURIComponent function as the encoding method: if (!encodeMethod) encodeMethod = encodeURIComponent; c14.indd 544c14.indd 544 8/20/07 6:13:49 PM8/20/07 6:13:49 PM [...]... content of the StringBuilder in a pop-up box: alert(builder.toString()); If you run the page shown in Listing 1 4-1 6 and enter 0 for the second number, you’ll get the pop-up box shown in Figure 1 4-2 , which displays the contents of the previously mentioned StringBuilder 560 c14.indd 560 8/20/07 6:13:54 PM Chapter 14: Consuming Web Services Via JSON Messages Figure 14 -2 Calling Page Methods As you saw... parameters: result = new Sys.Net.WebServiceError(false, result.Message, result.StackTrace, result.ExceptionType); Listing 1 4-1 4 presents the definition of the WebServiceError class 554 c14.indd 554 8/20/07 6:13:52 PM Chapter 14: Consuming Web Services Via JSON Messages Listing 1 4-1 4: The WebServiceError Class Sys.Net.WebServiceError = function Sys$Net$WebServiceError(timedOut, message, stackTrace, exceptionType)... only to SOAP messages Listing 1 4-1 2: The Web Service Used by Listing 1 4-1 1 using using using using using System; System.Web; System.Web.Services; System.Web.Services.Protocols; System.Web.Script.Services; (continued) 551 c14.indd 551 8/20/07 6:13:51 PM Chapter 14: Consuming Web Services Via JSON Messages Listing 1 4-1 2 (continued) namespace MyNamespace... detail later in this chapter 545 c14.indd 545 8/20/07 6:13:49 PM Chapter 14: Consuming Web Services Via JSON Messages onComplete As you saw in Listing 1 4-7 , the invoke static method of the WebServiceProxy class registers the onComplete private JavaScript function as the event handler for the completed event of the WebRequest object that represents the current request Listing 1 4-1 0 shows the internal... servicePath = “/AJAXFuturesEnabledWebSite2/PageMethods.aspx”; 561 c14.indd 561 8/20/07 6:13:54 PM Chapter 14: Consuming Web Services Via JSON Messages Listing 1 4-1 7: A Page that Allows You to Invoke its Methods from Your Client Code ... of the previously mentioned three-step procedure requires you to create a new file with extension asbx that describes the Math custom class defined in Listing 1 4-1 8 Listing 1 4-1 9 presents the contents of the Math.asbx file As you can see, an asbx file is just an XML file Listing 1 4-1 9: The.asbx File that Describes the Math Custom Class . timeout, as shown in Listing 1 4-2 . c14.indd 535c14.indd 535 8/20/07 6:13:45 PM8/20/07 6:13:45 PM Chapter 14: Consuming Web Services Via JSON Messages 536 Listing 1 4-2 : Getting and Setting the. some changes in the nor- mal ASP. NET Web service–handling infrastructure to enable it to process requests coming from the ASP. NET AJAX applications, because the normal ASP. NET Web service handler. System.Web.Script.Services; (continued) Figure 14 -1 c14.indd 551c14.indd 551 8/20/07 6:13:51 PM8/20/07 6:13:51 PM Chapter 14: Consuming Web Services Via JSON Messages 552 Listing 1 4-1 2 (continued) namespace