Пришёл век эпохи Web 2.0. Обычные решения на основе WebForms уже перестают соответствовать современным требованиям к web-проектам. Что-же нам предлагает Microsoft? Хм, достаточно мощное решение - Microsoft ASP.NET AJAX. Давайте попробуем создать простейшее приложение и посмотрим как оно устроено. Первое, что необходимо сделать, это создать проект типа ASP.NET Web Application. Затем создадим папку под наш будущий контрол, я на назвал её "MyControl".Далее нам понадобится добавить туда 4 файла: MyControl.cs, MyControl.debug.js, MyControl.js, MyControlService.asmx.

добавление .js файла

MyControl.cs - отвечает за серверную инициализацию контрола. MyControl.debug.js, MyControl.js - клиентский код. Файл .debug.js содержит полную клиентскую debug-версию разрабатываемого контрола,в отличие от MyControl.js, в котором должен содержаться упакованный javascript-код. ASP.NET автоматизированно вызывает тот или иной клиентский код, в зависимости от режима запуска проекта: debug или release.

файлы проекта

Файл MyControlService.asmx является WebService'ом и отвечает за обработку Ajax-запросов к серверу нашего контрола, на клиенте вызовы осуществляются с помощью класса Sys.Net.WebServiceProxy. Итак, MyControl.cs:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.UI;  
  6. using System.ComponentModel;  
  7.   
  8. namespace WebApplication1.MyControl  
  9. {  
  10.     public class MyControlScript : System.Web.UI.ScriptReference  
  11.     {  
  12.         public MyControlScript()  
  13.             : base("~/MyControl/MyControl.js") {  
  14.             ScriptMode = ScriptMode.Inherit;  
  15.         }  
  16.     }  
  17.   
  18.     public class MyControl : ScriptControl  
  19.     {  
  20.         [UrlProperty]  
  21.         [DefaultValue("")]  
  22.         public string ServicePath { getset; }  
  23.   
  24.         protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors() {  
  25.             if (string.IsNullOrEmpty(ServicePath))  
  26.                 throw new InvalidOperationException("'ServicePath' must be specified");  
  27.   
  28.             var control = new ScriptControlDescriptor("WebApplication1.MyControl.MyControl"this.ClientID);  
  29.             control.AddProperty("servicePath", ResolveUrl(ServicePath));  
  30.   
  31.             yield return control;  
  32.         }  
  33.   
  34.         protected override IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences() {  
  35.             return new ScriptReference[]  
  36.             {  
  37.                 new MyControlScript()  
  38.             };  
  39.         }  
  40.   
  41.         public override void RenderBeginTag(HtmlTextWriter writer) {  
  42.         }  
  43.   
  44.         public override void RenderEndTag(HtmlTextWriter writer) {  
  45.         }  
  46.   
  47.         protected override void RenderContents(HtmlTextWriter writer) {  
  48.   
  49.             writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);  
  50.             writer.RenderBeginTag(HtmlTextWriterTag.Div);  
  51.             writer.Write("<a href=\"#\" id=\""+this.ClientID+"_anchor\">получить данные с сервера</a>");  
  52.             writer.RenderEndTag();  
  53.         }  
  54.     }  
  55. }  

Класс ScriptControl отвечает за клиент-серверное связывание контролов. Наследник ScriptControl должен реализовать два метода: GetScriptDescriptors и GetScriptReferences. Первый возвращает объект ScriptDescriptor, содержащий в себе описание клиентского контрола(пространство имен и имя класса,перечень свойств, которые необходимо инициализировать). В нашем случае мы заполняем свойство "servicePath", хранящее адрес WebService'а. GetScriptReferences нужен для автоматизации подключения всех скриптов, требуемых для нашего контрола, причем все скрипты подключаются автоматизированно через ScriptManager и отпадает проблема дублирования клиентских скриптов на странице. Теперь посмотрим на клиентский код:

  1. ///<reference name="MicrosoftAjax.js" />  
  2.   
  3. Type.registerNamespace("WebApplication1.MyControl");  
  4.   
  5. WebApplication1.MyControl.MyControl = function(element) {  
  6.     WebApplication1.MyControl.MyControl.initializeBase(this, [element]);  
  7.     this._servicePath = '';  
  8.     var id = element.id;  
  9.     this._anchor = document.getElementById(id + '_anchor');  
  10. }  
  11.   
  12. WebApplication1.MyControl.MyControl.prototype = {  
  13.     initialize: function() {  
  14.     WebApplication1.MyControl.MyControl.callBaseMethod(this'initialize');  
  15.         var _this = this;  
  16.         this._anchor.onclick = function() {  
  17.             Sys.Net.WebServiceProxy.invoke(_this.get_servicePath(),  
  18.                     'GetData'falsenull,  
  19.                     function(data) {  
  20.                         window.alert(data);  
  21.                     }, function(error) {  
  22.                         window.alert('При получении данных произошла ошибка:'+error._message);  
  23.                     }  
  24.                 );  
  25.         };  
  26.         // Add custom initialization here  
  27.     },  
  28.     ///ServicePath  
  29.     get_servicePath: function() {  
  30.         return this._servicePath;  
  31.     },  
  32.     set_servicePath: function(value) {  
  33.         this._servicePath = value;  
  34.     },  
  35.     dispose: function() {  
  36.         //Add custom dispose actions here  
  37.         WebApplication1.MyControl.MyControl.callBaseMethod(this'dispose');  
  38.     }  
  39. }  
  40. WebApplication1.MyControl.MyControl.registerClass('WebApplication1.MyControl.MyControl', Sys.UI.Control);  
  41.   
  42. if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();          

Вся инициализация локальных переменных происходит в конструкторе, туда же и приходит html-объект element для которого создается экземпляр контрола. Объявление вида "///<reference name="MicrosoftAjax.js" />" необходимо для подсказок(IntelliSense) редактора Visual Studio. В методе initialize мы подвязываем клиентские обработчики, в данном случае использую анонимную функцию. По нажатию на ссылку, используя класс Sys.Net.WebServiceProxy производим вызов метода "GetData" нашего WebService'а. И обрабатываем 2 результата: выполнилось успешно и произошла ошибка. В случае возникновения исключительной ситуации подробную информацию о причине ошибки можно получить из объекта класса Exception. Код WebService'а выглядит следующим образом:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Web;  
  5. using System.Web.Services;  
  6.   
  7. namespace WebApplication1.MyControl  
  8. {  
  9.     [WebService(Namespace = "http://tempuri.org/")]  
  10.     [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]  
  11.     [System.ComponentModel.ToolboxItem(false)]  
  12.     [System.Web.Script.Services.ScriptService] // необходимо для клиентского связывания  
  13.     public class MyControlService : System.Web.Services.WebService  
  14.     {  
  15.         [WebMethod]  
  16.         public string GetData() {  
  17.             return "Мой первый ajax <b style="color: black; background-color: rgb(160, 255, 255);">контрол</b> :)";  
  18.         }  
  19.     }  
  20. }  

Здесь мы видим простой метод, возвращающий строку. Результат выполнения вызова WebMethod'а при нажатии на сслыку будет выглядеть следующим образом:

Microsoft Ajax в действии

Код инициализации клиентского контрола, сгенерированного ASP.NET:

  1. <script type="text/javascript">  
  2.     //<![CDATA[  
  3.     Sys.Application.initialize();  
  4.     Sys.Application.add_init(function() {  
  5.         $create(WebApplication1.MyControl.MyControl, { "servicePath""/MyControl/MyControlService.asmx" }, nullnull, $get("control"));  
  6.     });  
  7.     //]]>  
  8. </script>  

Желаю удачи в освоении Web 2.0!

Visual Studio 2008 Solution Скачать пример к статье (17 кб.)