通过jQuery或ScriptManager以Ajax方式访问服务

1、客户端和服务端

服务端对外提供服务时,可以通过handler或者webservice。handler比较轻便,但是难以对外公开,只有程序员自己知道它到底做了些什么工作。webservice可以将服务对外公开,调用也方便,更加专业些。如果不是要公开的接口,handler完全可以胜任了。下面是将webservice发布的效果。

客户端在调用服务端的服务时,最简单的莫过于使用jQuery了。当然微软也提供了ScriptMananger来访问WebService。他们之间的关系可以用下图说明。

2、搞一个Handler

 1 using System;
 2 using System.Collections;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 using System.Web.Script.Serialization;
 7 
 8 namespace WjjStudy.handler
 9 {
10     /// <summary>
11     /// info 的摘要说明
12     /// </summary>
13     public class info : IHttpHandler
14     {
15 
16         public void ProcessRequest(HttpContext context)
17         {
18             //提取参数
19             //context.Request.QueryString["name"];
20             //context.Request.Form["name"];
21             
22             //json 的 contentType 常见写法有 : text/json & text/javascript .
23             //但是 这个 text/json 其实是根本不存在的, 而 text/javascript 在有些时候客户端处理起来会有歧义. 
对于json的contentType , rfc里定义的标准写法是 :application/json.在这里毫无疑问 我们应该选择标准写法的 application/Json。
24 //如果指定为text/json, 处理方式:firefox,下载;chrome,直接显示。 25 context.Response.ContentType = "application/json";//只有具体指定了,firefox的json插件才起作用! 26 //context.Response.Write("{\"name\":\"wjj\",\"age\":\"25\"}"); 27 Hashtable ht = new Hashtable(); 28 ht["name"] = "wjj"; 29 ht["age"] = "21"; 30 31 JavaScriptSerializer js = new JavaScriptSerializer(); 32 string json = js.Serialize(ht); 33 context.Response.Write(json); 34 } 35 36 public bool IsReusable 37 { 38 get 39 { 40 return false; 41 } 42 } 43 } 44 }

3、搞一个WebService

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.Web.Script.Serialization;
 6 using System.Web.Script.Services;
 7 using System.Web.Services;
 8 using WjjStudy.model;
 9 
10 namespace WjjStudy.asmx
11 {
12     /// <summary>
13     /// info 的摘要说明
14     /// </summary>
15     [WebService(Namespace = "http://gagarin.org/")]
16     [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
17     [System.ComponentModel.ToolboxItem(false)]
18     // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 
19     [System.Web.Script.Services.ScriptService]
20     public class info : System.Web.Services.WebService
21     {
22 
23         [WebMethod(Description = "返回类型是对象")]
24         public Student GetStudent(int para)
25         {
26             return new Student { ID = para, Name = "wjj" };
27             //{"d":{"__type":"WjjStudy.model.Student","ID":100,"Name":"wjj"}}
28         }
29 
30         [WebMethod(Description = "返回类型是字符串")]
31         //[ScriptMethod(ResponseFormat = ResponseFormat.Json, XmlSerializeString = false)] 没用
32         public string GetStudentJson(int para)//返回给客户端为json字符串,需要将该字符串再次序列化。
33         {
34             //1、拼凑JSON字符串
35             //return "{\"ID\":" + para + ",\"Name\":\"wjj\"}";
36 
37             //2、借助JavaScriptSerializer
38             //this.Context.Request.ContentType = "application/json";//没用
39             //this.Context.Response.ContentType = "application/json";//没用
40 
41             JavaScriptSerializer jss = new JavaScriptSerializer();
42             return jss.Serialize(new Student { ID = para, Name = "wjj" });
43             //{"d":"{\"ID\":100,\"Name\":\"wjj\"}"}
44         }
45     }
46 }

4、jQuery访问Handler

jQuery访问Handler,只要调用$.ajax({}),将url传递进去就ok了,比较简单,就不演示了。当然如果你不怕麻烦你可以使用JS原生的XMLHttpRequest来访问它。

 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 5     <title>xmlhttprequest实现ajax访问</title>
 6     <script type="text/javascript">
 7         function createXHR() {
 8             var xhr = null;
 9             try {
10                 // Firefox, Opera 8.0+, Safari,IE7+
11                 xhr = new XMLHttpRequest();
12             }
13             catch (e) {
14                 // Internet Explorer 
15                 try {
16                     xhr = new ActiveXObject("Msxml2.XMLHTTP");
17                 }
18                 catch (e) {
19                     try {
20                         xhr = new ActiveXObject("Microsoft.XMLHTTP");
21                     }
22                     catch (e) {
23                         xhr = null;
24                     }
25                 }
26             }
27             return xhr;
28         }
29         //在收到响应后相应数据会填充到XHR对象的属性,有四个相关属性会被填充:
30         //1. responseText:作为响应主体被返回的文本
31         //2. responseXML:如果响应内容的类型是”text/xml”或”application/xml”,这个属性将保存包含着相应数据的XML文档
32         //3. status:响应的HTTP状态(200,404,500等)
33         //4. statusText:HTTP状态说明
34         var xhr = createXHR();
35         //检查XHR对象的readyState属性,该属性表示请求/响应过程中的当前活动阶段,每当readyState值改变的时候都会触发一次onreadystatechange事件。必须在open前就指定该处理函数。
36         xhr.onreadystatechange = function () {
37             //readyState 
38             //0:请求未初始化;
39             //1:服务器已建立连接;
40             //2:请求已接受;
41             //3:请求处理中;
42             //4:请求已完成,且响应就绪。
43             if (xhr.readyState == 4 && xhr.status == 200) {
44                 console.log('Original Ajax: ' + xhr.responseText);
45             }
46         }
47         xhr.open('post', '../handler/info.ashx', true);//get或post,ashx需要发布后才可以访问
48         xhr.setRequestHeader("userdef", "haha");//open后,send前
49         xhr.send('{para:100}');
50     </script>
51 </head>
52 <body>
53 </body>
54 </html>

5、使用jQuery和ScriptManager访问WebService及比较

这里才是本文想说的重点呢。因为有好几个地方需要注意,否则很纠结。以下是本人测试得到的结论,仅供参考。

测试的代码如下(由于用到了ScriptManager,这是一个aspx文件):

  1 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="testAjax.aspx.cs" Inherits="WjjStudy.aspx.testAjax" %>
  2 
  3 <!DOCTYPE html>
  4 
  5 <html xmlns="http://www.w3.org/1999/xhtml">
  6 <head runat="server">
  7     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  8     <title>jquery、ScriptManager调用WebService</title>
  9     <script src="../js/jquery-1.8.3.min.js"></script>
 10     <script>
 11         //请求类型默认是application/json
 12         function ajaxGo() {//默认返回json
 13             //全路径:命名空间.类名.方法名。不管参数名,按照顺序匹配。
 14             WjjStudy.asmx.info.GetStudent(100, function (result) {
 15                 console.log(result);//默认就是json
 16             }, function () {
 17                 console.error("访问失败。");
 18             });
 19 
 20             WjjStudy.asmx.info.GetStudentJson(100, function (result) {
 21                 console.log(result);//默认就是json
 22             }, function () {
 23                 console.error("访问失败。");
 24             });
 25         }
 26 
 27         //请求类型默认是application/x-www-form-urlencoded; charset=UTF-8
 28         function jqAjaxGo() {//默认返回xml,如何改成json?
 29             //1、返回xml
 30             $.ajax({
 31                 type: 'post',//默认只支持post,如果需要支持get,需要配置web.config
 32                 url: '../asmx/info.asmx/GetStudent',
 33                 async: true,
 34                 data: { "para": 1000 },
 35                 success: function (result) {
 36                     console.log(result);
 37                 },
 38                 error: function () {
 39                     console.error("访问失败。");
 40                 }
 41             });
 42             //2、返回xml
 43             $.ajax({
 44                 type: 'post',//默认只支持post,如果需要支持get,需要配置web.config
 45                 url: '../asmx/info.asmx/GetStudentJson',
 46                 async: true,
 47                 data: { para: 1000 },
 48                 success: function (result) {
 49                     console.log(result);
 50                 },
 51                 error: function () {
 52                     console.error("访问失败。");
 53                 }
 54             });
 55 
 56             //如何换成json?大量的尝试后
 57             //不管有没有配置web.config,使用get方法均报错:尝试使用 GET 请求调用方法“GetStudent”,但不允许这样做。
 58             //所以只能post,不能get。
 59 
 60             $.ajax({
 61                 type: 'post',
 62                 url: '../asmx/info.asmx/GetStudent',
 63                 async: true,
 64                 data: '{para:1000}',
 65                 //1、参数列表必须同名,不区分大小写 PARa也行。不管顺序,按照参数名匹配。
 66                 //2、如果指定contentType: 'application/json;charset=UTF-8',直接写{para:1000}报错->无效的para json基元。需要写成'{}'
 67                 contentType: 'application/json;charset=UTF-8',//指定contentType才有效,dataType不指望。
 68                 dataType: 'json',//期待返回的类型,服务器会先 根据返回的数据推断,如果推断不了才会用这里的dataType。一般而言,都可以根据头信息推断出来,所以这里dataType几乎没用。
 69                 success: function (result) {
 70                     console.log(result);
 71                 },
 72                 error: function () {
 73                     console.error("访问失败。");
 74                 }
 75             });
 76 
 77             $.ajax({
 78                 type: 'post',
 79                 url: '../asmx/info.asmx/GetStudentJson',
 80                 async: true,
 81                 data: '{ para: 1000 }',
 82                 contentType: 'application/json;charset=UTF-8',
 83                 success: function (result) {
 84                     console.log(result);
 85                 },
 86                 error: function () {
 87                     console.error("访问失败。");
 88                 }
 89             });
 90 
 91 
 92         }
 93     </script>
 94 </head>
 95 <body>
 96 
 97     <form id="form1" runat="server">
 98         <%--注册脚本,会生成很多其他js--%>
 99         <asp:ScriptManager ID="clientService" runat="server">
100             <Services>
101                 <asp:ServiceReference Path="~/asmx/info.asmx" />
102             </Services>
103         </asp:ScriptManager>
104 
105         <div id="container">
106             <input type="button" value="ScripManager Test Ajax" onclick="ajaxGo();" />
107             <br />
108             <input type="button" value="jQuery Test Ajax" onclick="jqAjaxGo();" />
109             <br />
110         </div>
111     </form>
112 </body>
113 </html>

执行效果 :

点击ScriptManager Text Ajax:

点击jQuery Text Ajax按钮

注意点1

webservice默认只支持post请求,如果要支持get请求,需要配置web.config,在system.web节点中加入以下配置

 1 <configuration>
 2     <system.web>
 3         <compilation debug="true" targetFramework="4.0" />
 4         <!--加上以下节点,避免Get请求时(默认只支持HttpPost)报错:因 URL 意外地以“/GetStudent”结束,请求格式无法识别。-->
 5         <webServices>
 6             <protocols>
 7                 <add name= "HttpPost" />
 8                 <add name= "HttpGet" />
 9             </protocols>
10         </webServices>
11     </system.web>
12 
13 </configuration>

注意点2

 jQuery在发送ajax请求时,请求类型默认是application/x-www-form-urlencoded; charset=UTF-8,webservice默认则会返回xml格式的字符串,如果我们想返回json格式的怎么搞?

我在客户端发送Ajax请求时,设置dataType:'json',可惜没用,我猜测它的本质含义是:期待返回的类型,服务器会先 根据返回的数据推断,如果推断不了才会用这里的dataType。一般而言,都可以根据头信息推断出来,所以这里dataType几乎没用。然后在服务器端设置Response.ContentType="application/json",也不奏效。当然了,同时设置也没有结果...

后来我设置contentType:'application/json',貌似看到了希望,可是报错:无效的para json基元,后来测试(很久时间)发现需要将{para:1000}写成'{para:1000}'才可以。

注意点3

设置了contentType:'application/json'可以返回json字符串了,但是只能使用post方法,不管你的web.config是否有配置。否则报错:尝试使用 GET 请求调用方法“GetStudent”,但不允许这样做。

注意点4

通过ScriptManager来访问WebService时,查看源文件,会发现给你生成很多的JS,开发虽然是简单了,但是这么多的js一定程度上消耗更多的性能,网页加载的速度变慢、数据量增大不可避免了。所以推荐使用jQuery!

6、总结

个人认为最佳模式是jQuery加上WebService,但是我还是习惯于jQuery加上Handler。我觉得这篇文章最有意义的还是如何让返回的xml改成返回json。如果你能够亲自动手做一下,相信会有更深的体会,因为代码里写了较多的注释,会帮助你理解。

 

参考链接:ASP.NET 使用Ajax

 

posted @ 2014-05-17 19:24  凌晨风  阅读(769)  评论(0编辑  收藏  举报