среда, 16 марта 2016 г.

Основы создания веб сервисов

В нынешние времена бурного развития интренета все чаще и чаще возникает проблема связи между данными, расположенными в разных концах земногошара на различных платформах и в разнообразных источниках данных. И эта проблема все больше увеличивается с ростом компаний, использующих интернет и веб приложения в своем бизнесе. Microsoft .NET веб сервисы решают проблему такой связи.

Не вдаваясь в глубины теории веб сервисов и вопросы о том, как и почему они работают, данная статья целиком и полностью посвящена вопросу создания веб сервисов. В течении нескольких последующих страниц будут рассмотрены многие аспекты создания веб сервисов и написано небольшое приложение, использующее технологию веб сервисов.
Итак, как же выглядит веб сервис для разработчика? Первое – файл web-сервиса имеет расширение asmx. Второе – создание web-сервиса немногим отличается от создания веб-формы в .NET Framework. Третье – файл веб сервиса должен начинаться с директивы WebService. Четвертое – класс web-сервиса может (но не должен) быть потомком класса System.Web.Services.Webservice. Ну и последнее (пока что) – метод, вызываемый через веб, должен имет атрибут WebMethod.
Основываясь на вышесказанном начнем реализовывать веб сервис (все примеры в этой главе основаны на codebehind и сделаны с помощью Visual Studio.NET).
Создадим новое приложение в VS.NET и добавим к нему файл веб сервиса nw.asmx (ну или откроем notepad и создадим 2 файла – nw.asmx и nw.asmx.cs).

Файл nw.asmx содержит единственную строку – директиву WebService, которая утверждает, что этот файл – действительно веб сервис. Этот файл меняться не будет, так что можете взглянуть на него и пока забыть :).
<%@ WebService Language="c#" Class="WebServicesExample.nw" %>
Весь код веб сервиса будет располагаться в codebehind файле nw.asmx.cs. Изначально этот файл (созданный в Visual Studion.NET) имеет следующий вид:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;

namespace WebServicesExample
{
 /// <summary>
 /// Summary description for nw.
 /// </summary>
 public class nw : System.Web.Services.WebService
 {
  public nw()
  {
   //CODEGEN: This call is required by the ASP.NET Web Services Designer
   InitializeComponent();
  }

  #region Component Designer generated code
  
  //Required by the Web Services Designer 
  private IContainer components = null;
    
  /// <summary>
  /// Required method for Designer support - do not modify
  /// the contents of this method with the code editor.
  /// </summary>
  private void InitializeComponent()
  {
  }

  /// <summary>
  /// Clean up any resources being used.
  /// </summary>
  protected override void Dispose( bool disposing )
  {
   if(disposing && components != null)
   {
    components.Dispose();
   }
   base.Dispose(disposing);  
  }
  
  #endregion

  // WEB SERVICE EXAMPLE
  // The HelloWorld() example service returns the string Hello World
  // To build, uncomment the following lines then save and build the project
  // To test this web service, press F5

//  [WebMethod]
//  public string HelloWorld()
//  {
//   return "Hello World";
//  }
 }
}
Как видите ребята из Microsoft сразу же позаботились о начинающих программистах и лишили работы многие поколения учителей, жутко любивших начинать свои рассказы с крика «Hello, World!» :). Теперь вы сами не прилагая никаких усилий можете создать этот код просто откомментировав объявление метода HelloWorld() :).
Ну что ж, сделаем это (зря, что ли ребята старались? :) и запустим, предварительно откомпилировав проект, на выполнение наш веб сервис (откроем в браузере страницу http://localhost/WebServicesExample/nw.asmx). В браузере нарисуется вот такая страница:

ASP.NET для отображения web-сервиса использует файл шаблона DefaultWsdlHelpGenerator.aspx, расположенный в папке %SYSTEM_ROOT%\Microsoft.NET\Framework\<номер версии Microsoft .NET Framework>\CONFIG. На выводимой странице веб сервиса есть название веб сервиса (отмечено 1), ссылка на описание сервиса (2) (эта ссылка в дальнейшем будет интересовать нас при создании клиентов к веб сервису) и список веб методов, объявленных в веб сервисе (3). Остальная часть страницы посвящена тому, как плохо использовать неймспейс по умолчанию для веб сервиса, и рекомендациям срочно исправить это упущение :). Нет проблем и пока это свежо у нас в памяти поступим как рекомендуют – добавим атрибут WebService с параметром Namespace к классу веб сервиса:
[WebService(Namespace="http://www.aspnetmania.com/webservices")]
Итак, перейдем к странице описания web-метода SayHello (просто кликните по ссылке SayHello на странице описания web-сервиса).

Как видите на ней также присутствует название веб сервиса, ссылка на первую страницу веб сервиса, название веб метода. Кроме этого на странице расположена форма, предназначеная для вызова web метода через GET запрос (данное правило не выполняется, если web метод не может быть вызван таким образом) и примеры запросов для вызова данного веб метода с помощью SOAP, HTTP POST (если такой вызов возможен) и HTTP GET (если такой вызов возможен). Также представлены примеры ответов вызова web метода.
При желании вы можете сейчас протестировать метод нажав на кнопку Invoke (у меня уже такого желания нет :)). Лучше перейдем к созданию более полезных веб методов.
Я долго думал какой же веб метод предложить первым для изучения. Что-то простое, возвращающее единственное значение, или помонструозней да с DataSetами? И решил все таки в первом же примере показать как можно больше возможностей веб сервисов.
Итак, задача – торговая фирма, имеющая БД со всеми необходимыми ей для работы данными (ну как тут без Northwind обойтись :)), открывает филиал в другом районе/городе/конце земного шара. При этом возникает естесственная потребность работникам филиала обеспечить доступ к БД фирмы. Но вокруг одни ограничения – база централизована и копию создавать нельзя, а в филиале вообще всего пара компьютеров, которые только и могут, что выйти в интернет. Но работать им как-то с базой все таки надо... :). Хотя бы иметь возможность получать заказы по указанным клиентам.
Задача поставлена, теперь необходимо ее реализовывать. Для начала мы создадим веб сервис, возвращающий DataSet с заказами указанного клиента, а потом напишем 2 клиента для этого веб сервиса, один на DHTML для IE, второй на ASP.NET (через некоторое время филиал все таки разбогател и купил себе компьютер для веб сервера :)).
Для получения интересующих нас данных мы будем использовать несколько измененную хранимую процедуру CustOrdersOrders:
CREATE PROCEDURE CustOrdersOrdersDetails 
@CustomerID nchar(5)
AS
SELECT 
 OrderID, 
 OrderDate,
 RequiredDate,
 ShippedDate
FROM 
 Orders
WHERE 
 CustomerID = @CustomerID
ORDER BY 
 OrderID
SELECT     
 Products.ProductName, 
 [Order Details].UnitPrice, 
 [Order Details].Quantity, 
 [Order Details].Discount, 
 [Order Details].OrderID
FROM
 [Order Details] INNER JOIN Products ON 
 [Order Details].ProductID = Products.ProductID
where
 OrderID in (SELECT OrderID FROM Orders WHERE CustomerID = @CustomerID)
Веб метод, возвращающий данные по выбранному клиенту, имеет следующий вид:
[WebMethod]
public DataSet GetCustOrders(string CustomerID)
{
 SqlConnection myConn = new SqlConnection("server=localhost;database=Northwind;uid=sa;pwd=Manowar");
 SqlDataAdapter myData = new SqlDataAdapter("CustOrdersOrdersDetails", myConn);
 myData.SelectCommand.CommandType = CommandType.StoredProcedure;
 myData.SelectCommand.Parameters.Add(new SqlParameter("@CustomerID", SqlDbType.Char, 5));
 myData.SelectCommand.Parameters["@CustomerID"].Value = CustomerID;

 DataSet ds = new DataSet();
 myData.Fill(ds);
 ds.Tables[0].TableName = "Orders";
 ds.Tables[1].TableName = "OrderDetails";
 ds.Relations.Add(ds.Tables[0].Columns["OrderID"], ds.Tables[1].Columns["OrderID"]);
 return ds;
}
Ничего экстраординарного – DataSet заполняется данными, полученными вызовом созданной нами хранимой процедуры, к нему добавляется отношение между таблицами и затем результат возвращается. Ну и естесственный атрибут WebMethod для метода говорит о том, что мы сможем вызвать этот метод из веб сервиса.
Протестируем нашу работу с помощью страницы веб сервиса. Откройте в браузере страницы веб сервиса (у меня этоhttp://localhost/WebServicesExample/nw.asmx), нажмите на GetCustOrders для перехода с странице веб метода, введите в поле ввода ID клиента из базы Northwind (например ALFKI) и нажмите кнопку Invoke. Откроется новая страница, содержащая в себе XML. Это и есть результат вызова нашего веб метода – необходимый нам DataSet со списком заказов клиента ALFKI. Ниже представлены фрагменты страницы с результатами.
<?xml version="1.0" encoding="utf-8"?>
<DataSet xmlns="http://www.aspnetmania.com/webservices">
    <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
        <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:Locale="uk-UA">
            <xs:complexType>
                <xs:choice maxOccurs="unbounded">
                    <xs:element name="Orders">
                        <xs:complexType>
                            <xs:sequence>
                                <xs:element name="OrderID" type="xs:int" minOccurs="0" />
                                <xs:element name="OrderDate" type="xs:dateTime" minOccurs="0" />
                                <xs:element name="RequiredDate" type="xs:dateTime" minOccurs="0" />
                                <xs:element name="ShippedDate" type="xs:dateTime" minOccurs="0" />
                            </xs:sequence>
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="OrderDetails">
                    …
                    </xs:element>
                </xs:choice>
            </xs:complexType>
            <xs:unique name="Constraint1">
                <xs:selector xpath=".//Orders" />
                <xs:field xpath="OrderID" />
            </xs:unique>
            <xs:keyref name="Relation1" refer="Constraint1">
                <xs:selector xpath=".//OrderDetails" />
                <xs:field xpath="OrderID" />
            </xs:keyref>
        </xs:element>
    </xs:schema>
    <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" 
    xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
        <NewDataSet xmlns="">
            <Orders diffgr:id="Orders1" msdata:rowOrder="0">
                <OrderID>10643</OrderID>
                <OrderDate>1997-08-25T00:00:00.0000000+03:00</OrderDate>
                <RequiredDate>1997-09-22T00:00:00.0000000+03:00</RequiredDate>
                <ShippedDate>1997-09-02T00:00:00.0000000+03:00</ShippedDate>
            </Orders>
            <Orders diffgr:id="Orders2" msdata:rowOrder="1">
                <OrderID>10692</OrderID>
                <OrderDate>1997-10-03T00:00:00.0000000+03:00</OrderDate>
                <RequiredDate>1997-10-31T00:00:00.0000000+02:00</RequiredDate>
                <ShippedDate>1997-10-13T00:00:00.0000000+03:00</ShippedDate>
            </Orders>
            …
            <OrderDetails diffgr:id="OrderDetails1" msdata:rowOrder="0">
                <ProductName>Rössle Sauerkraut</ProductName>
                <UnitPrice>45.6</UnitPrice>
                <Quantity>15</Quantity>
                <Discount>0.25</Discount>
                <OrderID>10643</OrderID>
            </OrderDetails>
            <OrderDetails diffgr:id="OrderDetails2" msdata:rowOrder="1">
                <ProductName>Chartreuse verte</ProductName>
                <UnitPrice>18</UnitPrice>
                <Quantity>21</Quantity>
                <Discount>0.25</Discount>
                <OrderID>10643</OrderID>
            </OrderDetails>
            …
        </NewDataSet>
    </diffgr:diffgram>
</DataSet>
Рассмотрим повнимательней что же нам верноул веб метод.
Из приведенного выше кода можно сделать следующие выводы:
  • Возвращаемый результат имеет тип DataSet (это видно как из названия корневого узла, так и из строки <xsd:element name="NewDataSet" msdata:IsDataSet="true" msdata:Locale="uk-UA"> в описании схемы).
  • Возвращаемый DataSet содержит 2 таблицы – Orders и OrderDetails.
  • В схеме доступна полная онформация о таблицах, а также запись о созданном нами отношении между таблицами.
Конечно же, если бы нам для вызова web-метода приходилось заходить на страницу его описания, вручную задавать параметры вызова web-метода и вызывать его, толку от этого было бы мало. Как я уже говорил, web-методы можно вызывать с помощью HTTP GET, HTTP POST и SOAP запросов.
Сейчас мы рассмотрим возможности работы с созданным web-сервисом с помощью HTTP GET (или HTTP POST) из браузера Internet Explorer (тот самый случай, когда работники филиала нашей гипотетической фирмы не имеют ничего кроме компьютера с выходом в интернет), а также SOAP вызов с помощью небольшой программы, написанной на C#.
Как же это делается? Воспользуемся объектом Microsoft.XMLHTTP, позволяющим передавать и получать данные с помощью запросов GET или POST. Мы создаем запрос к соответствующему web-методу нашего web-сервиса, передаем (если необходимо) параметры и выводим на страницу полученный в ответ XML код, используя небольшой xsl-файл.
Ниже представлен код orders.xsl (предназначенного для отображения полученного результата) и DhtmlClient.htm (основного файла).
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <xsl:template match="/">
  <xsl:for-each select="//Orders">
    <xsl:variable name="currOrder" select="OrderID" />
    <TABLE BORDER="1" width="100%">
      <TR><TD valign="top"><B>Order:</B></TD><TD valign="top"><xsl:value-of select="OrderID" /></TD></TR>
      <TR><TD valign="top"><B>Date:</B></TD><TD valign="top"><xsl:value-of select="OrderDate" /></TD></TR>
      <TR><TD valign="top"><B>Ship:</B></TD><TD valign="top"><xsl:value-of select="ShippedDate" /></TD></TR>
      <tr><td colspan="2" align="right">
      <table><tr><td>Product:</td><td>Price:</td><td>Quantity:</td><td>Discount:</td></tr>
      <xsl:for-each select="//OrderDetails[./OrderID=$currOrder]" >
        <TR>
        <TD valign="top"><xsl:value-of select="ProductName" /></TD>
        <TD valign="top"><xsl:value-of select="UnitPrice" /></TD>
        <TD valign="top"><xsl:value-of select="Quantity" /></TD>
        <TD valign="top"><xsl:value-of select="Discount" /></TD></TR>
      </xsl:for-each>
      </table>
      </td></tr>
    </TABLE>
  </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>
<HTML>
 <HEAD>
  <TITLE></TITLE>
  <SCRIPT LANGUAGE="JScript">
         var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

         var objStyle = new ActiveXObject("MSXML.DOMDocument");
         objStyle.async = false;
         objStyle.load("orders.xsl");

         var SOAPRequest = new ActiveXObject("MSXML.DOMDocument");
         SOAPRequest.async = false;

         var SOAPResponse = new ActiveXObject("MSXML.DOMDocument");
         SOAPResponse.async = false;

         function getOrders()
         {
         // xmlhttp.Open("GET", "http://localhost/WebServicesExample/nw.asmx/GetCustOrders?CustomerID=" + 
         // document.all.client.value, false);
            xmlhttp.Open("POST", "http://localhost/WebServicesExample/nw.asmx/GetCustOrders", false);
   xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
   xmlhttp.send("CustomerID=" + document.all.client.value);
   SOAPResponse.loadXML(xmlhttp.responseXML.xml);
            document.all.orders.innerHTML = SOAPResponse.transformNode(objStyle.documentElement);
         }
  </SCRIPT>
 </HEAD>
 <BODY>
  <TABLE cellSpacing="2" cellPadding="2" align="center" border="0">
   <TR>
    <TD>Клиент</TD>
    <TD>
     <INPUT id="client" type="text" name="client"></TD>
    <TD>
     <INPUT type="button" value="Заказы" onclick="getOrders();"></TD>
   </TR>
  </TABLE>
  <div id="orders" align="center"></div>
 </BODY>
</HTML>
Откройте файл DhtmlClient.html в броузере, введите код клиента в поле ввода (ALFKI подойдет просто замечательно) и нажмите кнопку «Заказы». JavaScript метод getOrders() направит запрос через HTTP POST к веб методу и затем преобразует возвращенный результат с помощью таблицы стилей orders.xsl и выведет его на страницу (если вы хотите протестировать вызов веб метода через HTTP GET – откомментируйте первую строку метода и закомментируйте три последующих). При этом у вас получится страница, похожая на вот это:

Теперь рассмотрим вызов web-метода из .NET-приложения. Для вызова web-сервисов .NET-приложение использует прокси-класс, генерируемый либо с помощью утилиты командной строки wsdl, либо с помощью добавления Web Reference в проект Visual Studio .NET. Прокси-класс, генерируемый таким образом, содержит довольно много кода. Но для нас представляет ценность то, что в нем содержатся методы для вызова интересующих нас web-методов.
Напишем небольшое Windows Forms приложение, вызывающее метод GetCustOrders нашего веб сервиса. В Visual Studio.NET создадим Windows приложение. Добавим в созданное приложение ссылку на web-сервис (меню Project – Add Web Reference…). В адресную строку открывшегося окна введем адрес нашего web-сервиса (http://localhost/WebServicesExample/nw.asmx):

После нажатия на кнопку Add Reference Visual Studio.NET добавит в проект ссылку на web-сервис и автоматически сгенерирует прокси-класс для вызова web-методов.
Тем, кто не пользуется Visual Studio.NET, создание прокси класса также не представляет особого труда. Для этого, как я уже говорил, используется утилита командной строки wsdl. Полное описание использования этой утилиты можно найти в MSDN, здесь же я только покажу вызов этой утилиты для генерации прокси класса для нашего веб сервиса.
wsdl /l:cs http://localhost/WebServicesExample/nw.asmx
При этом будет создан файл nw.cs, содержащий небходимый нам прокси класс.
Продолжим создание Windows клиента для форума. Разместим на форме поле ввода для ввода кода клиента, DataGrid для отображения полученных данных и, естесственно, кнопку «Заказы». Для того, чтобы в DataGridе отобразились интересующие нас данные, в обработчик OnClick кнопки необходимо вставить всего 2 строки:
private void btnOrders_Click(object sender, System.EventArgs e)
{
 localhost.nw orders = new localhost.nw();
 dgMain.DataSource = orders.GetCustOrders(txtClient.Text);
}
Запустите созданное приложение, введите ALFKI в поле ввода и нажмите кнопку «Заказы». В DataGridе отобразится полученный в результате вызова DataSet с интересующими нас данными:

Как видите создание и использование web-сервисов в .NET не такая уж и сложная задача.
Теперь рассмотрим строение web-сервиса, что называется, шаг за шагом.
В первой (и единственной, если вы пишете с использованием технологии codebehind) строке asmx файла, как и в случае с aspx-файлом, расположена директива ASP.NET, указывающая на тип данного файла, язык, на котором написан код, и имя класса для файла. Например строка для написанного нами web-сервиса следующая:
<%@ WebService Language="c#" Class="WebServicesExample.nw" %>
где директива WebService указывает на то, что данный файл является web-сервисом, а атрибуты Language=”c#” и Class=”WebServicesExample.nw” указывают на то, что класс web-сервиса написан на C# и полное имя класса – WebServicesExample.nw.
Web-сервис может состоять из множества классов. Однако только один класс в web-сервисе может иметь методы, помеченные атрибутом WebMethod (которые можно вызывать через SOAP-запросы).
Атрибут WebMethod имеет шесть свойств, влияющих на работу web-метода. Рассмотрим их:

Description

Данное свойство служит для общего описания web-метода. Вы можете присвоить данному свойству любую текстовую строку. Значение свойства Description выводится на странице описания web-сервиса. Возвращаясь к рассмотренному ранее примеру опишем web-метод getAuthors следующим образом:
[WebMethod(Description="Возвращает список заказов для указанного клиента")]
public DataSet GetCustOrders(string CustomerID)
Откомпилируем наш проект и взглянем теперь на страницу описания web-сервиса:

Как видите, теперь под методом GetCustOrders выведено его описание.

EnableSession

Данное свойство позволяет включить поддержку сессий. По умолчанию поддержка сессий в web-сервисах отключена. Чтобы включить ее, определите web-метод следующим образом:
[WebMethod(EnableSession=true)]
Если при объявлении web-сервиса вы породили его от класса System.Web.Services.WebService, то вы автоматически получаете доступ к открытым свойствам Application, Context, Session, Server и User, имеющим такой же смысл, как и аналогичные свойства ASP.NET веб форм. Если же вы создавали класс web-сервиса как-то иначе – ничего страшного. Вы все равно можете получить доступ к вышеперечисленным свойствам с помощью соответствующих свойств статического HttpContext.Current.
Рассмотрим работу с объектами Application и Session на примере. Напишем небольшой web-сервис с двумя web-методами – setSessionVar (принимает 2 строковых параметра – имя переменной сессии и ее значение, и устанавливает переменную сессии) и getSessionVar (принимает строковый параметр – имя сессии, и возвращает значение переменной сессии):
[WebMethod(EnableSession=true)]
public void setSessionVar(string name, string val)
{
   Session[name] = val;
}

[WebMethod(EnableSession=true)]
public string getSessionVar(string name)
{
   return (string) Session[name];
}
Не забывайте, что ASP.NET определяет сессию по идентификатору сессии, хранящемуся в cookie. Так что приведенный выше пример будет успешно работать из страницы web-сервиса, но если попробовать вызывать методы этого web-сервиса из .NET приложения через прокси-класс, то вы с удивлением обнаружите, что вызов метода getSessionVar не возвращает никакого значения, так как использование web-сервисов с помощью проки-класса по умолчанию не использует куки для сохранения информации.
Чтобы .NET приложение могло работать с сессией с помощью web-сервиса, необходимо добавить в код, вызывающий методы web-сервиса, работу с cookie. И это не так уж сложно, как кажется на первый взгляд :).
Создадим Windows приложение, добавим в него Web Reference на созданный ранее web-сервис и добавим интерфейс для установки переменных сессии с помощью метода setSessionVar и получения значения переменной сессии с помощью getSessionVar. Объявим также в класс приватную переменную cookie типа CookieContainer (класс CookieContainer описан в модуле System.Net). В конструкторе класса проиницализируем эту переменную. Теперь для того, чтобы вызовы методов web-сервиса были в одной сессии, необходимо просто перед вызовом web-метода присвоить значение cookie свойству CookieContainer класса web-сервиса.
Полностью код вызова веб методов с использованием cookie представлен ниже (прокси-класс, сгенерированный для web-сервиса, имеет название localhost1.testService1):
private CookieContainer cookie;

public Form1()
{
    InitializeComponent();
    cookie = new CookieContainer();
}


private void btnSetValue_Click(object sender, System.EventArgs e)
{
 localhost.session session = new localhost.session();
 session.CookieContainer = cookie;
 session.setSessionVar(txtSessionName.Text, txtSessionValue.Text);
}

private void btnGetValue_Click(object sender, System.EventArgs e)
{
 localhost.session session = new localhost.session();
 session.CookieContainer = cookie;
 txtSessionValue.Text = session.getSessionVar(txtSessionName.Text); 
}

MessageName

Свойство MessageName позволяет назначать web-методу имя, отличное от того, которое ему было назначено при написании класса web-сервиса.
Существует возможность создавать в web-сервисе web-методы с одинаковыми именами. Но при попытке просмотра страницы такого web-сервиса будет сгенерирована ошибка. Свойство MessageName используется именно в этих случаях.
Допустим кроме веб метода GetCustOrders с одним параметром (код клиента) у нас объявлен еще один метод GetCustOrders, принимающий кроме кода клиента также вилку дат и возвращающий DataSet с информацией о заказах, дата которых находится между указанными датами
[WebMethod(Description=" Возвращает список заказов для указанного клиента ")]
public DataSet GetCustOrders(string CustomerID)
{
    ...
}
[WebMethod(MessageName="GetCustOrdersByDate")]
public DataSet GetCustOrders(string CustomerID, DateTime startDate, DateTime endDate)
{
    ...
}
Теперь, хотя оба web-метода и имеют одинаковое имя, все равно есть возможность использовать страницу web-сервиса. При этом в прокси классе оба метода естесственно будут определены с именем GetCustOrders.

TransactionOption

Web-сервисы ограниченно поддерживают транзакции. С помощью свойства TransactionOption можно управлять тем, как ваш метод использует транзакции. Это свойство может принимать следующие значения:
DisabledВеб метод выполняется вне транзакции
NotSupportedТо же самое
SupportedЕсли транзакция существует – метод выполняется в контексте этой транзакции, если же нет – выполнение идет вне транзакции
RequiredМетод требует наличия транзакции для выполнения. При этом всегда создается новая транзакция (аналогично RequiresNew).
RequiresNewМетод требует создания новой транзакции. Каждый раз при вызове метода создается новая транзакция.
Слово «ограниченно» означает, что веб сервис может порождать транзакцию, но при этом не может быть участником другой транзакции. Если вызывается веб метод с TransactionOption установленным в Required или RequiresNew, а в нем вызывается другой веб метод с такими же установками, каждый из этих методов инициирует свою транзакцию.
По умолчанию свойство TransactionOption установлено в Required.
При нормальном завершении работы метода транзакция считается выполненной. Чтобы прервать выполнение транзакции, сгенерируйте исключение. В веб методе не нужно вызывать методы SetComplete и SetAbort.

CacheDuration

Сказать, что кеширование веб сервисов просто означало бы покривить душой. Кешировать веб сервисы не просто, а очень просто. Одним словом, все, что нужно для того, чтобы активизировать кеширование веб сервиса, это использовать параметр CacheDuration атрибута WebMethod с указанием промежутка времени в секундах, на которое кешируется веб сервис.
Ниже представлен пример обхъявления, кеширующий возвращаемое методом GetCustOrders значение на 10 минут.
[WebMethod(CacheDuration=600)]
public DataSet GetCustOrders(string CustomerID)

BufferResponse

Свойство BufferResponse позволяет управлять буферизацией ответа web-метода. По умолчанию результат выполнения буферизируется и отправляется клиенту только после того, как он полностью сформирован. Однако если ваш web-метод очень долго выполняется, возможно, имеет смысл отключать буферизацию результата.
Для отключения буферизации результата используйте следующее объявление web-метода:
[WebMethod(BufferResponse=false)]
public DataSet GetCustOrders(string CustomerID)

Параметры атрибута WebService

Web-сервис также имеет три свойства, влияющие на его работу. Два из них, Description и Name, работают точно так же, как и подобные им свойства Description и MessageName web-метода. Третье свойство, Namespace, позволяет управлять пространством имен в SOAP-сообщении. Рассмотрим применение всех трех свойств на примере web-сервиса wsauthors.
Изменим объявление web-сервиса на следующее:
[WebService(Description="Web-сервис для работы с клиентами", Namespace="http://www.aspnetmania.com/webservices", 
Name="NorthWindWebService")]
public class nw : System.Web.Services.WebService
после чего откомпилируем web-сервис и посмотрим на страницу описания:

На страницу было добавлено описание web-сервиса, введенное в свойстве Description, а также изменилось имя web-сервиса. Обратите внимание на тот факт, что теперь обращаться к web-сервису нужно по новому имени (вам необходимо будет заново сгенерировать прокси-класс для web-сервиса, и этот прокси-класс будет иметь новое имя).
И напоследок рассмотрим вопрос типов данных, которые может принимать в качестве параметров и возвращать веб метод.
Веб методы могут принимать как параметры и возвращать результатом любые значимые типы данных, массивы этих типов и структуры и классы, состоящие из этих типов. Если говорить проще, то web-сервис умеет работать с любым типом данных, который может быть представлен в виде XDR схемы.
Рассмотрим веб метод GetCustomer, возвращающий структуру Customer, содержащую информацию о клиенте. Для начала определим класс Customer
public class Customer
{
 private string id;
 private string companyName;
 private string address;
 public Customer()
 {
 }
 public Customer (string id, string companyName, string address)
 {
  this.id = id;
  this.companyName = companyName;
  this.address = address;
 }
 public string ID
 {
  get
  {
   return id;
  }
  set
  {
   id = value;
  }
 }
 public string CompanyName
 {
  get
  {
   return companyName;
  }
  set
  {
   companyName = value;
  }
 }
 public string Address
 {
  get
  {
   return address;
  }
  set
  {
   address = value;
  }
 }
}
В принципе ничего сложного – приватные переменные, публичные свойства простого типа и пара конструкторов. Не удивляйтесь наличию конструктора без параметров, хоть он и ничего реально не делает, но наличие публичного конструктора по умолчанию – требование сериализируемым классам. Вообщем наш класс полностью удовлетворяет требованиям, налагаемым на типы для использования их в веб сервисах.
Теперь напишем веб метод, возвращающий переменную данного типа.
[WebMethod(Description="Возвращает информацию о клиенте по его ключу")]
public Customer GetCustomer(string CustomerID)
{
 SqlConnection myConn = new SqlConnection("server=localhost;database=Northwind;uid=sa;pwd=Manowar");
 SqlCommand myCmd = new SqlCommand("select CustomerID, CompanyName, Address from Customers " +
   "where CustomerID = '" + CustomerID + "'", myConn);
 myConn.Open();
 SqlDataReader reader = myCmd.ExecuteReader();
 Customer customer;
 if(reader.Read())
  customer = new Customer(reader.GetString(0), reader.GetString(1), reader.GetString(2));
 else
  customer = new Customer();
 reader.Close();
 myConn.Close();
 return customer;
}
В результате вызова этого веб метода для многострадального клиента ALFKI будет возвращен следующий XML.
<?xml version="1.0" encoding="utf-8"?>
<Customer xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.aspnetmania.com/webservices">
  <ID>ALFKI</ID>
  <CompanyName>Alfreds Futterkiste</CompanyName>
  <Address>Obere Str. 57</Address>
</Customer>
Еще один вопрос, связанный с возвратом данных из web-сервиса, касается вида XML-кода, возвращаемого web-методом. Как видно из предыдущго примера, web-метод возвращает данные в виде XML-элементов с названиями, соответствующими тем названиям, которые были описаны в описании класса. Вы можете изменить как названия XML-элементов, так и возвращать некоторые (или все) данные в виде XML-атрибутов.
Изменим немного описание структуры Customer для иллюстрации сказанного. Теперь поле CustomerID, будет возвращаться как атрибут ID, а поле CompanyName поменяет свое название на Company.
public class Customer
{
...
[System.Xml.Serialization.XmlAttribute("ID")]
 public string ID
 ...
 [System.Xml.Serialization.XmlElement("Company")]
 public string CompanyName
 ...
}
Теперь в результате выполнения предыдущего web-метода через веб интерфейс будет получен следующий XML:
<?xml version="1.0" encoding="utf-8"?>
<Customer xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="ALFKI" 
xmlns="http://www.aspnetmania.com/webservices">
  <Company>Alfreds Futterkiste</Company>
  <Address>Obere Str. 57</Address>
</Customer>

Заключение

Веб сервисы представляют собой новый вид веб приложений для создания уровня бизнес логики и связи разнородных приложений с помощью использования общих стандартов – HTTP, XML и SOAP. Практически не существует ограничений на области применения веб сервисов: вы можете создавать веб сервисы для взаимодействия между различными приложениями или для предоставления данных вашим клиентам. Возможности использования веб сервисов теоретически ограничены только вашим воображением.
Текст примеров данной статьи можно выкачать здесь

Комментариев нет:

Отправить комментарий