Пришёл век эпохи 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.
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:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.ComponentModel;
-
- namespace WebApplication1.MyControl
- {
- public class MyControlScript : System.Web.UI.ScriptReference
- {
- public MyControlScript()
- : base("~/MyControl/MyControl.js") {
- ScriptMode = ScriptMode.Inherit;
- }
- }
-
- public class MyControl : ScriptControl
- {
- [UrlProperty]
- [DefaultValue("")]
- public string ServicePath { get; set; }
-
- protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors() {
- if (string.IsNullOrEmpty(ServicePath))
- throw new InvalidOperationException("'ServicePath' must be specified");
-
- var control = new ScriptControlDescriptor("WebApplication1.MyControl.MyControl", this.ClientID);
- control.AddProperty("servicePath", ResolveUrl(ServicePath));
-
- yield return control;
- }
-
- protected override IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences() {
- return new ScriptReference[]
- {
- new MyControlScript()
- };
- }
-
- public override void RenderBeginTag(HtmlTextWriter writer) {
- }
-
- public override void RenderEndTag(HtmlTextWriter writer) {
- }
-
- protected override void RenderContents(HtmlTextWriter writer) {
-
- writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
- writer.RenderBeginTag(HtmlTextWriterTag.Div);
- writer.Write("<a href=\"#\" id=\""+this.ClientID+"_anchor\">получить данные с сервера</a>");
- writer.RenderEndTag();
- }
- }
- }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.ComponentModel;
namespace WebApplication1.MyControl
{
public class MyControlScript : System.Web.UI.ScriptReference
{
public MyControlScript()
: base("~/MyControl/MyControl.js") {
ScriptMode = ScriptMode.Inherit;
}
}
public class MyControl : ScriptControl
{
[UrlProperty]
[DefaultValue("")]
public string ServicePath { get; set; }
protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors() {
if (string.IsNullOrEmpty(ServicePath))
throw new InvalidOperationException("'ServicePath' must be specified");
var control = new ScriptControlDescriptor("WebApplication1.MyControl.MyControl", this.ClientID);
control.AddProperty("servicePath", ResolveUrl(ServicePath));
yield return control;
}
protected override IEnumerable<System.Web.UI.ScriptReference> GetScriptReferences() {
return new ScriptReference[]
{
new MyControlScript()
};
}
public override void RenderBeginTag(HtmlTextWriter writer) {
}
public override void RenderEndTag(HtmlTextWriter writer) {
}
protected override void RenderContents(HtmlTextWriter writer) {
writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.Write("<a href=\"#\" id=\""+this.ClientID+"_anchor\">получить данные с сервера</a>");
writer.RenderEndTag();
}
}
}
Класс ScriptControl отвечает за клиент-серверное связывание контролов. Наследник ScriptControl должен реализовать два метода: GetScriptDescriptors
и GetScriptReferences. Первый возвращает объект ScriptDescriptor, содержащий в себе
описание клиентского контрола(пространство имен и имя класса,перечень свойств, которые необходимо инициализировать). В нашем случае
мы заполняем свойство "servicePath", хранящее адрес WebService'а. GetScriptReferences
нужен для автоматизации подключения всех скриптов, требуемых для нашего контрола, причем все
скрипты подключаются автоматизированно через ScriptManager и отпадает проблема дублирования
клиентских скриптов на странице. Теперь посмотрим на клиентский код:
-
-
- Type.registerNamespace("WebApplication1.MyControl");
-
- WebApplication1.MyControl.MyControl = function(element) {
- WebApplication1.MyControl.MyControl.initializeBase(this, [element]);
- this._servicePath = '';
- var id = element.id;
- this._anchor = document.getElementById(id + '_anchor');
- }
-
- WebApplication1.MyControl.MyControl.prototype = {
- initialize: function() {
- WebApplication1.MyControl.MyControl.callBaseMethod(this, 'initialize');
- var _this = this;
- this._anchor.onclick = function() {
- Sys.Net.WebServiceProxy.invoke(_this.get_servicePath(),
- 'GetData', false, null,
- function(data) {
- window.alert(data);
- }, function(error) {
- window.alert('При получении данных произошла ошибка:'+error._message);
- }
- );
- };
-
- },
-
- get_servicePath: function() {
- return this._servicePath;
- },
- set_servicePath: function(value) {
- this._servicePath = value;
- },
- dispose: function() {
-
- WebApplication1.MyControl.MyControl.callBaseMethod(this, 'dispose');
- }
- }
- WebApplication1.MyControl.MyControl.registerClass('WebApplication1.MyControl.MyControl', Sys.UI.Control);
-
- if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
///<reference name="MicrosoftAjax.js" />
Type.registerNamespace("WebApplication1.MyControl");
WebApplication1.MyControl.MyControl = function(element) {
WebApplication1.MyControl.MyControl.initializeBase(this, [element]);
this._servicePath = '';
var id = element.id;
this._anchor = document.getElementById(id + '_anchor');
}
WebApplication1.MyControl.MyControl.prototype = {
initialize: function() {
WebApplication1.MyControl.MyControl.callBaseMethod(this, 'initialize');
var _this = this;
this._anchor.onclick = function() {
Sys.Net.WebServiceProxy.invoke(_this.get_servicePath(),
'GetData', false, null,
function(data) {
window.alert(data);
}, function(error) {
window.alert('При получении данных произошла ошибка:'+error._message);
}
);
};
// Add custom initialization here
},
///ServicePath
get_servicePath: function() {
return this._servicePath;
},
set_servicePath: function(value) {
this._servicePath = value;
},
dispose: function() {
//Add custom dispose actions here
WebApplication1.MyControl.MyControl.callBaseMethod(this, 'dispose');
}
}
WebApplication1.MyControl.MyControl.registerClass('WebApplication1.MyControl.MyControl', Sys.UI.Control);
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'а выглядит
следующим образом:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Services;
-
- namespace WebApplication1.MyControl
- {
- [WebService(Namespace = "http://tempuri.org/")]
- [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
- [System.ComponentModel.ToolboxItem(false)]
- [System.Web.Script.Services.ScriptService]
- public class MyControlService : System.Web.Services.WebService
- {
- [WebMethod]
- public string GetData() {
- return "Мой первый ajax <b style="color: black; background-color: rgb(160, 255, 255);">контрол</b> :)";
- }
- }
- }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
namespace WebApplication1.MyControl
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService] // необходимо для клиентского связывания
public class MyControlService : System.Web.Services.WebService
{
[WebMethod]
public string GetData() {
return "Мой первый ajax контрол :)";
}
}
}
Здесь мы видим простой метод, возвращающий строку. Результат выполнения вызова WebMethod'а
при нажатии на сслыку будет выглядеть следующим образом:
Код инициализации клиентского контрола, сгенерированного ASP.NET:
- <script type="text/javascript">
-
- Sys.Application.initialize();
- Sys.Application.add_init(function() {
- $create(WebApplication1.MyControl.MyControl, { "servicePath": "/MyControl/MyControlService.asmx" }, null, null, $get("control"));
- });
-
- </script>
<script type="text/javascript">
//<![CDATA[
Sys.Application.initialize();
Sys.Application.add_init(function() {
$create(WebApplication1.MyControl.MyControl, { "servicePath": "/MyControl/MyControlService.asmx" }, null, null, $get("control"));
});
//]]>
</script>
Желаю удачи в освоении Web 2.0!
Скачать пример к статье (17 кб.)