通过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