Як не потрібно писати веб сервіси

Микита Зімін

Суммар нашого досвіду використання технології. Net XML Web Services, представлений у вигляді “від протилежного”.

Як НЕ треба писати веб-сервісу


З усього багатого арсеналу платформи. Net поки найбільш затребуваними виявилися технології ASP.Net і Web Services, використовувані для написання серверних додатків. До масового написання на. Net клієнтських додатків справу ще не дійшло, хоча повідомлення про це вже пояляться.


З ASP.Net все зрозуміло – її можна розглядати просто як зручну заміну ASP. Що стосується web-services – що ж це насправді?


Відразу обмовлюся, що в рамках цієї статті ми розглядаємо тільки “XML Web
Services Created Using ASP.NET”.


Функціонально, Web Service – це клас, зі своїм набором властивостей і методів, які доступні для виклику через віддалене з’єднання по протоколу HTTP. При кожному виклику як запит, так і відповідь представляється у вигляді XML. Більш докладний опис ви знайдете в статті [1].


Перші спроби серйозного застосування нової технології разом з радістю новизни приносять і свій негативний досвід. Реклама (а часто і документація) розхвалює зручність і красу, нічого не кажучи про обмеження і недоліки. Тим не менше така інформація важлива – вона поряд з набором можливостей окреслює сферу застосування технології.


Цей текст узагальнює досвід використання веб-сервісів в наших проектах. Я не претендую на повноту або істину в останній інстанції. Не забувайте що немає правил без винятків. Мені лише хотілося б щоб ви не повторили описаних тут помилок.

Веб-сервіс як клас

У самому справі – веб-сервіс представляється класом. Він породжується від класу System.Web.Services.WebService, має свої властивості та методи. А раз це клас, то можна створювати екземпляри об’єктів цього класу. Тоді можна робити і так:

    Dim ws As FooWS.Foo = New FooWS.Foo
    ws.Login(name, password)
    ws.GetData()
    ws.SaveData()
    ws.Logout()

Начебто все чудово – за одним винятком. Змінна ws зберігає посилання на об’єкт, але це – не примірник веб-сервісу – адже той об’єкт може бути створений тільки на сервері. Викликом New FooWS.Foo ми створюємо proxy-клас, звернення до якого призводять до викликів веб-методів.

У загальному випадку, при кожному виклику екземпляр (об’єкт) класу FooWS.Foo створюється на сервері заново. А значить, значення, що зберігаються в цьому об’єкті, втрачаються. Тим самим, стан цього об’єкта не зберігається між викликами (що і називається “stateless”).


Оскільки клас є stateless, то й писати його потрібно відповідно:


Спадкування на веб-сервісах

Як і для будь-яких інших повноцінних класів, для веб-сервісів можна застосовувати спадкування. Ви навіть можете скласти цілу ієрархію таких класів. Про перевагах говорити не буду – скажу тільки про недоліки.


Скільки б не було у вас веб-сервісів – 1 або 100, розташовуються вони в одному проекті або в декількох – але щоб використовувати їх десь ще окрім вашого проекту ви повинні на КОЖЕН з них встановити посилання (web-reference). Це кілька обмежить ваші можливості як великого об’єктного архітектора.


Кожна web-reference задає свій namespace (наприклад, у наведеному вище прикладі посилання буде називатися FooWS і namespace матиме ту ж назву). Якщо ви породите два класи (наприклад, Foo1 і Foo2) від одного батьківського класу (Foo, породженого від WebService), то для їх використання на клієнті вам доведеться завести два посилання (FooWS1 і FooWS2), причому об’єкти, оголошені в проекті веб-сервісу глобально, будуть доступні на клієнті під двома іменами (в нашому прикладі FooWS1.MyDataSet і FooWS2.MyDataSet). Це тільки ускладнює програмування і нічого корисного в собі не несе.


Отже.


Спадкування на веб-сервісах не дає нам фактично нічого, крім нових проблем. Інкапсуляція даних в клас веб-сервісу безглузда – оскільки ці дані не зберігаються між викликами. Виходить, що від об’єктного підходу, стосовно до веб-сервісів, практично нічого не залишається.


Скоріше це бібліотека статичних методів, зібраних в одному модулі під одним ім’ям, причому виклики цих методів досить “важкі” (не в сенсі труднощі в реалізації або використання, а в сенсі ефективності).

Передача параметрів: Упаковка параметрів в рядок або XML

VB6, що передує своєму наскрізь об’єктному побратиму VB.Net, накладав певні (і досить суворі) обмеження на передачу структур даних у вигляді параметрів методів і в якості значень, що повертаються. Ці правила тим більше суворі якщо мова йде про межкомпонентних викликах.


Тому для VB-програміста є звичним і природним передавати складні дані якимось іншим способом – наприклад, упакувавши всі параметри в рядок. Більш того, галас навколо XML призводить до того що багато хто вважає природним упаковувати і параметри, і результат, у формат XML.


VB.Net позбавлений недоліку свого “молодшого” побратима – ви можете як передавати, так і повертати складні структури даних. Для веб-сервісу автоматично створюється proxy-клас, вирішальний проблеми перетворення будь-яких переданих типів і структур в / з XML. І запит, породжуваний викликом, і результат передаються в вигляді XML.


Тим самим, ручна упаковка в / з рядка чи (тим більше) XML тільки додасть зайвий код – а можливо і зайві помилки.


[Тут треба зауважити, що складні об’єктні структури (передавані web-сервісів або повертаються від них) можуть створюватися на основі додаткової бібліотеки класів, або використовувати можливості DataSet. У будь-якому випадку, бібліотека класів або схема даних DataSet має бути присутня і на сервері, і на клієнті.]

Використання веб-сервісу як компонента

Припустимо що архітектура нашої системи полягає (повністю або в основному) з веб-сервісів. Тоді кожен веб-сервіс розглядається в якості окремого компонента, що виконує свою функцію. Ця функція чітко визначена, різні компоненти можуть писати різні люди. Загалом, отримуємо всі достоїнства компонентного підходу.


У чому ж недоліки цього шляху?



  1. Виклики веб-методів дуже важкі.
    Виклик методу веб-сервісу – довга пісня: параметри пакуються в XML, виконується запит до веб-сервера, на якому підвантажується сторінка, за нею знаходиться і підвантажується код, вхідні параметри створюються з XML, нарешті працює сам метод, а потім – те ж саме в зворотну сторону. Таким чином, накладні витрати на кожний виклик дуже великі. Затримки при викликах можуть іноді обчислюватися секундами.
    Така технологія дозволяє виконувати виклик використовуючи протокол HTTP, працювати через firewall, але навіщо вам усе це, якщо компоненти вашої системи знаходяться на одному комп’ютері або в локальній мережі? Подумайте, може бути краще використовувати COM +-компоненти? – Їх теж можна написати на. Net.
  2. Методи веб-сервісу не можуть бути частиною транзакції
    Компоненти завжди пов’язані між собою, і виклик методу одного модуля часто призводить до виникнення кількох викликам в “нижележащих” компонентах.
    Важливо знати, що виклик веб-сервісу не може бути частиною транзакції. Кожен веб-сервіс функціонує в своєму середовищі і стан сесії, пов’язане з транзакцією, не передається.
    Це означає, що сценарій відновлення даних у базі з подальшим прийняттям / відкатом (Commit / rollback) тут непридатний: відкат (rollback) змін, зроблених в ході виклику веб-методу, не відбудеться.
    Тим не менш, в рамках одного веб-методу транзакція може бути створена. Див [2].
    [Дотепер стандарти по транзакціях і безпеки у відношенні до веб-сервісів знаходяться в розробці – це обмежує область їх застосування. У даний момент будь-яке рішення цих проблем буде забезпечуватися не стандартними, а пропрієтарними засобами – це теж треба враховувати.]

Резюме – а як треба?

Питання про те, чи доцільно використання тієї чи іншої технології, завжди можна вирішити тільки стосовно до конкретної задачі. Але можна заздалегідь сказати, що web-service буде хорошим рішенням в якомусь із наступних умов:



Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*