AJAX с помощью jQuery и ASP.NET web-сервисов
Если вы создаете сайты под ASP.NET, то возможно вам уже довелось использовать AJAX-framework, предоставляемый Microsoft. Тот самый, что использует ScriptManager, rfк в примере, приведенном ниже:
1) Содержимое страницы Default.aspx:
<asp:ScriptManager ID="MainSM" ScriptMode="Debug" runat="server"> <Services> <asp:ServiceReference Path="~/usersrv.asmx" InlineScript="false" /> </Services> </asp:ScriptManager>
2) Содержимое файла script.js:
// вызов ajax-метода GetPoint usersrv.GetPoint(id,OnUSGetPointSucc,OnUSGetPointErr); // callback успешного вызова function OnUSGetPointSucc(res) { alert('success'); } // callback ошибки function OnUSGetPointErr(err) { alert('success'); }
3) Содержимое файла usersrv.asmx:
<%@ WebService Language="C#" CodeBehind="~/App_Code/usersrv.cs" %>
4) Содержимое файла usersrv.cs:
[WebService(Namespace = "http://tempuri.org/")] [System.Web.Script.Services.ScriptService] public class usersrv : System.Web.Services.WebService { [WebMethod] public Dictionary<string, object> GetPoint(long p_id) { Dictionary<string, object> res = new Dictionary<string, object>(); try { // готовим возвращаемые параметры и сохраняем их в res } catch (Exception) { res["Error"] = U.GTFR("userpoints_err"); } return res; } }
Этот метод достаточно прост и удобен, если бы не одно “но” – он весит 132 Кб. И обладает еще одним интересным свойством: если в нашем проекте есть несколько страниц, использующих AJAX, то каждая из них будет заново загружать этот скрипт, потому что при загрузке скрипта на странице используется примерно следующий URL http://domainname/ScriptResource.axd?d=TvjJs2RlM8MX3pIUhEsdnZKUzGh-9Wr9nvNBZJbxf-xzq-Wvzbpj6FfMJqZqOPR8Pku52J2zBqleUlYtVE8XCyfyo3kcbSnhbwzYc2LkdfQ1&t=ffffffffee41303f и для каждой страницы в пределах вашего проекта будет свой ScriptManager, а значит и свой уникальный ID в query-string. А значит скрипт этот для каждой страницы будет браться не из кэша, а запрашиваться заново с сервера.
В общем, мне все это не понравилось и я заинтересовался, как можно сэкономить трафик и перейти на AJAX.jQuery. Тем более, что он уже использовался в этом же проекте для других целей. Сказано – сделано! И вот какое решение я нашел.
Собственно, модификации пришлось подвергнуть как сами клиентские JavaScript-ы, так и методы, вызываемые на стороне сервера. Связано это с тем, что мне хотелось передавать в качестве параметров для web-сервиса сложные объекты, а не просто строки и целые значения. И получать в ответ хотелось тоже сложные объекты, а не просто строки.
Все это можно легко и просто сделать, передавая как в ту так и в другую сторону все же строки, но строки в формате JSON, который является родным для JavaScript. Да к тому же ASP.NET обладает встроенными возможностями сериализации/десериализации JSON.
Правда, для сериализации объекта в JSON на клиентской стороне пришлось использовать еще одну дополнительную библиотеку json2.js. Таким образом, обе библиотеки весят около 67 Кб. Да плюс ко всему в случае нескольких ajax-страниц в проекте, скрипт загрузится всего один раз, и для остальных страниц будет браться из кэша браузера.
Но от слов – к делу! Вот содержимое скрипта, выполняемого на клиентской стороне:
// готовим передаваемые параметры в переменную par, здесь - всего лишь эмуляция var par = new Object(); par.a = 5; par.b = 'data'; par.c = new Array(); par.c[0] = 5; par.c[1] = 10; // сериализуем объект var ser = JSON.stringify(par); // формируем ajax-запрос $.ajax({ type: "POST", url: "usersrv.asmx/GetPoint", data: "{'par':'"+ser+"'}", contentType: "application/json; charset=utf-8", dataType: "json", success: function(r) { var res=r.d; // сериализуем для наглядности полученные данные и выводим их на страницу // в реальном приложении здесь мы просто будем использовать готовые данные // в переменной res без сериализации document.getElementById("result").innerHTML=JSON.stringify(r); }, error: function(err) { // обработка ошибки alert('error: '+err.responseText); } }); }
А вот содержимое usersrv.cs:
using System; using System.Collections; using System.Linq; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System.Xml.Linq; using System.Web.Script.Serialization; [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.Web.Script.Services.ScriptService] public class usersrv : System.Web.Services.WebService { public usersrv() { } [WebMethod] public ResponseType GetPoint(string par) { ResponseType response = new ResponseType(); RequestType request = new RequestType(); try { // десериализуем полученные параметры JavaScriptSerializer ser = new JavaScriptSerializer(); request = ser.Deserialize<RequestType>(par); } catch (Exception) { response.isError = true; response.message = "Parameters is invalid"; return response; } // преобразуем переданные параметры и готовим ответ // здесь - всего лишь эмуляция обработки данных if (request.c != null && request.a == request.c.Length) { response.isError = false; response.message = "That's good"; } else { response.isError = true; response.message = "Length is not the same"; } return response; } }
А вот описание двух воспомогательных классов:
public class RequestType { public int a; public string b; public int[] c; } public class ResponseType { public string message; public bool isError; }
Разумеется, они могут быть сколь угодно сложными. Думаю, что суть алгоритма ясна из комментариев в тексте программы.
Ссылка на архив с готовым проектом здесь.