Delphi разработка web приложений
Что такое WEB-сервис наверное знает каждый. WEB-сервисы не собственность компании Microsoft, а целый промышленный стандарт на основе открытых протоколов HTTP и SOAP, однако использование в качестве средства разработки платформы .NET позволит создавать WEB-сервисы очень быстро и просто.
- Выполняется на стороне сервера
- Предоставляет набор методов, доступных внешним клиентам.
- Исполняет WEB- методы и возвращает результаты клиентам
- WEB-сервис и его клиенты могут быть написаны на разных языках и/или разных платформах.
На этом позволим себе временно отстраниться от теории и перейти к практике
Простейший WEB-сервис
Давайте запустим Delphi 8 и создадим WEB-сервис, который назовем SampleWebService
Рис.1 Выбор типа создаваемого приложения
Рис.2 Диалог создания проекта.
Delphi 8 создаст для нас простейший WEB-сервис. Состав файлов в проекте WEB-сервиса требует отдельного описания, которое будет дано немного позже. Сейчас же рассмотрим файл WebService1.pas, который содержит описание класса TWebService1
TWebService1 = class(System.Web.Services.WebService) strict private ////// Required designer variable. /// components: IContainer; ////// Required method for Designer support - do not /// modify the contents of this method with /// the code editor. /// procedure InitializeComponent; strict protected ////// Clean up any resources being used. /// procedure Dispose(disposing: boolean); override; private < Private Declarations >public constructor Create; (* // Sample Web Service Method [WebMethod] function HelloWorld: string; *) end;
Обратите внимание на закомментированный метод WEB-метод HelloWorld, (WEB-метод он потому, что ему назначен атрибут [WebMethod]). Давайте попробуем раскоментировать его и его реализацию. Вот и все. Наш первый WEB-сервис готов. Как его протестировать? Очень просто, нажмите F9.
Результат не заставить себя долго ждать, вы увидите страницу подобную приведенной на рис. 3.
Рис 3. Автоматически сгенерированная страница-описание WEB-сервис
Как протестировать WEB-метод Вы наверное уже догадались? Если нет, то кликните по ссылке HelloWorld.
рис 4. Тестирование WEB-метода
После нажатия на кнопку «Invoke» наш WEB-сервис стартует и вернет потрясающий результат в виде XML:
Ну что ж, первой цели мы достигли: научились создавать простейший WEB-сервис, предоставляющий WEB-метод и все это успешно протестировано.
WEB-методы
Атрибут WebMethod
- CacheDuration — Кэширование результатов работы метода на заданное количество секунд. (например, метод с такими атрибутами будет хранить результат своей работы в течении 15 секунд : [WebMethod(CacheDuration=»15″)] ).
- Description — Добавляет текстовое описание WEB-метода.
- MessageName — Имя WEB-метода. Полезно, например, когда нужно опубликовать перегруженный метод класса.(наличие двух одноименных WEB-методов запрещено)
В качестве примера давайте добавим к нашему классу еще два метода и добавим описание к существующему методу HelloWorld:
TWebService1 = class(System.Web.Services.WebService) // Экономия места public constructor Create; // Sample Web Service Method [WebMethod (MessageName = 'HelloWorld' , Description = 'Простой метод')] function HelloWorld:String; [WebMethod (MessageName = 'IntegerSubstract')] function Substract(a,b:Integer):Integer;overload; [WebMethod (MessageName = 'FloatSubstract')] function Substract(a,b:Single):Single;overload; Реализация методов тривиальна: function TWebService1.Substract(a,b:Integer):Integer; begin Result := a - b; end; function TWebService1.Substract(a,b:Single):Single; begin Result:= a - b; end;
Запустите добавленные WEB-методы. Обратите внимание, что мы использовали механизм перегрузки функций, но при этом не пострадали от ограничений связанных с именованием WEB-методов: WEB-сервис предоставляет их как методы с различными именами.
Сложные типы данных в WEB-методах
Все то, что было показано до этого, выглядело неплохо. Однако на практике не очень часто приходится оперировать простыми типами данных, как это было показано в предыдущих примерах. Очень часто возникает необходимость вернуть сложный тип данных (например, объект).
На самом деле решение проблемы не представляет особых сложностей. Давайте попробуем ее решить. Итак, пусть нам необходимо создать сервис, возвращающий курс доллара за указанный промежуток времени.
Итак, курс доллара будет представлен следующим классом:
TDollarRate = class public Cost:Integer; Date:TDateTime; constructor Create; end; constructor TDollarRate.Create; begin inherited Create; Cost:=20 + Random(5); Date:=DateToStr(DateTime.Now); end;
Перед добавлением WEB-метода объявим тип TDollarRates = Array of TDollarRate, в секцию uses добавим Borland.Vcl.SysUtils. Метод имеет вид:
[WebMethod] function GetRatesForDays (ADays:Integer):TDollarRates; function TWebService1.GetRatesForDays (ADays:Integer):TDollarRates; var i:Integer; begin SetLength(Result,ADays); for i:=ADays-1 downto 0 do Result[i]:=TDollarRate.Create; end;
Попробуем протестировать метод (рис 5).
Рис. 5 Тестирование метода, возвращающего массив объектов Результат превзошел все ожидания:
-- 23 28.04.2004 -23 28.04.2004 -20 28.04.2004
В процессе разработки этого примера мы были неприятно удивлены одной деталью (версия Delphi 8 7.1.1146.610): мы попытались объявить новый конструктор с параметрами:
TDollarRate = class public Cost:Integer; Date:TDateTime; constructor Create(Adays:Integer); end; constructor TDollarRate.Create(Adays:Integer); var sDate:TDateTime; begin inherited Create; end;
и получили следующую ошибку при старте WEB-сервиса:
рис 6. Как же переопределить конструктор ?
Как сделать новый конструктор Default public в Delphi 8 не совсем понятно, однако выручило переименование конструктора следующим образом:
TDollarRate = class public Cost:Integer; Date:String; constructor TDollarRate(Adays:Integer); end;
Результат работы стал таким:
"?xml version="1.0" encoding="utf-8" ?> -- 21 26.04.2004 -24 26.04.2004
На этом описание WEB-методов завершается. Перед тем, как рассказать о том, каким образом клиентское приложение может взаимодействовать с нашим WEB-сервисом, а также каким образом оно будет «понимать» не только простые, но и «сложные» типы данных рассмотрим подробнее, из каких частей состоит WEB-сервис.
Архитектура WEB-сервиса
По большому счету WEB-сервис представляется всего одним файлом, с расширением Asmx , который должен как минимум иметь примерно такой заголовок:
Далее может идти код, собственно реализующий функциональность WEB-сервиса. Этот код должен быть написан на одном из языков .NET платформы (например C#).
К великому сожалению, создать WEB-сервис на Object-Pascal таким образом пока нельзя. Однако разработчики платформы .NET предусмотрели возможность перенести код WEB-сервиса в отдельно компилируемую DLL(фоновый код). Частично для того, чтобы была возможность разрабатывать WEB-приложения на языках, непосредственно не поддерживающих ASP.NET, частично для того, чтобы диагностировать ошибки компиляции до развертывания самого сервиса.
Автоматически сгенерированный файл .asmx, состоящий из заголовка примерно такого вида:
Как вы наверняка уже догадались для тестирования сервиса достаточно в браузере набрать строку
WSDL — язык описания WEB-сервисов.
Мы практически готовы к тому, чтобы перейти к созданию клиента для нашего WEB-сервиса. Нам осталось только узнать как сторонние разработчики (пользователи нашего сервиса) могут узнать какие методы поддерживает WEB-сервис, сигнатуры этим методов, URL сервиса, типы используемых данных. Вся эта информация описывается при помощи языка WSDL. Тем не менее, вам не придется его изучать, так как этот язык больше для компьютеров, не для людей. Как же получить описание нашего WEB-сервиса на языке WSDL? Да очень просто, достаточно ввести в браузере
Ниже приведено описание TDollarRates и TDollarRate нашего примера:
Создание клиента для WEB-сервиса.
После стольких усилий по изучению WEB-сервисов пришло время научится их использовать. Как и всегда ничего сложного в этом нет. В качестве примера создадим VCL Forms приложение. Его главная и единственная форма должна выглядеть примерно так:
Рис. 7. Форма Веб-Калькулятора
Осталось только «оживить» нашу форму. Для этого выберите пункт меню Project/Web Reference.
В диалоге, который откроется, укажите URL к WSDL описанию нашего сервиса В нашем случае это —
Нажмите кнопку «GO» а потом «AddReference».
Рис. 8. Добавление ссылки на WEB-сервис.
Прокси WEB-сервиса
В общем-то, ничего особенно не изменилось, за исключением того, что в проект был добавлен файл localhost.WebService1.pas, содержащий в себе класс TWebService1. Этот класс называется прокси WEB-сервиса, это локальный представитель WEB-сервиса для нашего клиентского приложения. Файл localhost.WebService1.pas сгенерирован автоматически, и менять его реализацию не рекомендуется, однако если посмотреть на него ближе (здесь приведена только секция interface) можно сделать некоторые выводы.
- Прокси WEB-сервиса не выполняет никаких действий, но переправляет вызовы методов WEB-сервису.
- Прокси обязательно должен знать, с каким WEB-сервисов он связан, что подтверждается реализацией его конструктора:
constructor TWebService1.Create; begin inherited Create; Self.Url := 'http://localhost/SampleWebService /WebService1.asmx'; end;
Вызов WEB-методов. Асинхронный режим.
Ниже приведен код нашего клиентского приложения, умеющего выполнить WEB-метод, и отобразить результат:
unit Umain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Borland.Vcl.StdCtrls, System.ComponentModel, localhost.WebService1; type TForm1 = class(TForm) Edit1: TEdit; Edit2: TEdit; Label1: TLabel; Label2: TLabel; Edit3: TEdit; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private FWEBProxy:TWebService1; < Private declarations >public < Public declarations >end; var Form1: TForm1; implementation procedure TForm1.FormCreate(Sender: TObject); begin FWEBProxy:=TWebService1.Create; end; procedure TForm1.Button1Click(Sender: TObject); begin Edit3.Text:= IntToStr(FWEBProxy.Substract (StrToInt(Edit1.Text),StrToInt(Edit2.Text) )); end; end.
Рис 9. Веб калькулятор в действии
Теперь давайте усложним задачу? Заставим метод Substract возвращать результат через определенное время? В этом случае наше клиентское приложение попросту будет «висеть» пока WEB-метод не отработает. Давай добавим в WEB-метод Substract нашего WEB-сервиса имитацию бурной деятельности:
function TWebService1.Substract(a,b:Integer):Integer; var i:Integer; begin Sleep(5000); Result := a - b; end;
Так вот теперь, если запустить наш калькулятор, он будет успешно зависать на почти пять секунд. Возможно, нам нужно выполнять программу дальше, даже если результат WEB-метода еще не получен? Для этого существует возможность вызвать метод асинхронно.
procedure TForm1.Button1Click(Sender: TObject); var asyncres:IAsyncResult; begin asyncres:=FWEBProxy.BeginSubstract (StrToInt(Edit1.Text), StrToInt(Edit2.Text),nil,nil); // какой-то код Edit3.Text:= IntToStr(FWEBProxy.EndSubstract (asyncres)); end;
procedure TForm1.Button1Click(Sender: TObject); var asyncres:IAsyncResult; begin asyncres:=FWEBProxy.BeginSubstract (StrToInt(Edit1.Text), StrToInt(Edit2.Text),nil,nil); while not asyncres.IsCompleted do Application.ProcessMessages; Edit3.Text:= IntToStr(FWEBProxy.EndSubstract (asyncres)); end;
unit Umain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Borland.Vcl.StdCtrls, System.ComponentModel, localhost.WebService1; type TForm1 = class(TForm) Edit1: TEdit; Edit2: TEdit; Label1: TLabel; Label2: TLabel; Edit3: TEdit; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private FWEBProxy:TWebService1; procedure SubstratctFinished (Res:IAsyncResult); < Private declarations >public < Public declarations >end; var Form1: TForm1; implementation procedure TForm1.FormCreate(Sender: TObject); begin FWEBProxy:=TWebService1.Create; end; procedure TForm1.Button1Click(Sender: TObject); begin FWEBProxy.BeginSubstract(StrToInt(Edit1.Text), StrToInt(Edit2.Text), SubstratctFinished,nil); end; procedure TForm1.SubstratctFinished (Res: IAsyncResult); begin Edit3.Text:= IntToStr (FWEBProxy.EndSubstract(Res)); end; end.
Заключение
В этой статье мы показали особенности создания WEB-сервисов при помощи Delphi 8. Надеемся, что она поможет Вам в работе.