• Применение промежуточного уровня для презентационной логики
  • Обработка данных на промежуточном уровне
  • Создание повторно используемых компонентов промежуточного уровня
  • Использование компонента в другом приложении
  • Доступ к объектам с помощью Web-служб
  • Публикация существующего компонента с помощью Web-службы
  • Доступ к Web-службе программными средствами
  • Заключительные замечания
  • Резюме
  • Вопросы и ответы
  • ГЛАВА 12

    Web-службы и технологии промежуточного уровня

    Вероятно, многие читатели или еще не работали с компонентами промежуточного уровня, или имеют опыт работы с приложениями, которые включают только Web-сервер и сервер баз данных, где большая часть прикладной логики содержится в ASP-страницах, а в базе данных хранится только используемая информация. Организацию системы, при которой прикладная логика находится на промежуточном уровне или распределена среди нескольких уровней, принято было называть канализацией (plumbing). В такой системе прикладная логика предоставляет пользователю все необходимые данные и службы, но полностью скрыта от него.

    В течение многих лет такая "канализация" реализовывалась с помощью DLL-файлов на языке Visual Basic или Visual C++. Используемый код имел вид откомпилированного объекта, который можно было применять совместно, повторно или удаленно. Наиболее распространенным примером частого повторного использования кода являются объявления объектов ADODB.Connection и ADODB.Recordset, которые принимают строку подключения и запрос и возвращают результирующий набор записей. Эту логику можно упаковать в виде функции, принимающей в качестве параметров строку подключения и запрос, а возвращающей результирующий набор записей. Теоретически этот способ просто прекрасен, но в реальной ситуации возникают проблемы с контролем версий, удаленным доступом и общим недопониманием в среде разработчиков.

    Компанией Microsoft достигнут невероятный прогресс в развитии промежуточного уровня в рамках платформы .NET Framework. Она открыла низкоуровневые библиотеки для всех языков программирования в среде VS.NET. В результате разработчики на языке Visual Basic получили гораздо более удобный и простой способ доступа к потокам и маршалингу для более эффективного управления производительностью. Следующим крупным шагом вперед было введение контроля версий на стороне сервера. Это позволяет хранить на одном компьютере проектируемую и рабочую версии кода без конфликтов между ними. Серверный контроль версий происходит благодаря тому, что на платформе .NET для их хранения используются разные каталоги, а не параметры системного реестра. Нельзя не упомянуть здесь и Web-службы. Хотя в эпоху интенсивного развития Internet эту технологию нельзя назвать совершенно новой, все же Web-службы, вероятно, являются наиболее перспективным путем развития идеологии распределенных вычислений. В данной главе рассматриваются механизмы работы промежуточного уровня и описываются способы его реализации.

    Применение промежуточного уровня для презентационной логики

    Данные, вводимые пользователем в Web-форму (например, дата), часто нуждаются в проверке на соответствие заданным требованиям. Большинству разработчиков известно, что эта простая задача может быть выполнена несколькими разными способами в клиентской части или на презентационном уровне. Однако это требование ограничивает клиентский код только языком HTML. В этом контексте становится ясным значение промежуточного уровня: именно на этом уровне происходит взаимодействие клиента с обрабатываемыми им данными.

    В Visual Basic .NET предусмотрена удобная встроенная функция IsDate для управления процессами проверки правильности формата введенной даты. Она возвращает логическое значение, которое определяет успешное или неудачное преобразование переданной ей информации в корректный формат даты. Рассмотрим подробнее эту функцию на более высоком уровне.

    Создадим Web-форму datecheck.aspx с помощью шаблона ASP.NET Web Application среды Visual Studio .NET. В данной Web-форме будут располагаться только два серверных элемента управления: текстовое поле и кнопка. После щелчка на кнопке введенная в текстовом поле информация передается серверу, на котором выполняется функция Is Date. Затем результат выполнения функции передается обратно Web-форме. В листинге 12.1 приводится вспомогательный код данной Web-формы datecheck.aspx.vb, а в листинге 12.2 — код самой Web-формы datecheck.aspx.

    ЛИСТИНГ 12 1. Вспомогательный код Web-формы datecheck.aspx.vb

    Public Class datecheck

     Inherits System.Web.UI.Page

     Protected WithEvents TextBox1 As System.Web.UI.WebControls.TextBox

     Protected WithEvents Button1 As System.Web.UI.WebControls.Button

    #Region " Web Form Designer Generated Code "

     ' Этот код создан конструктором Web-форм.

     <System.Diagnostics.DebuggerStepThrough()> Private Sub _

      InitializeComponent()

     End Sub


     Private Sub Page_Init(ByVal sender As System.Object, _

      ByVal e As System.EventArgs) Handles MyBase.Init

      ' CODEGEN: Этот вызов метода организован конструктором Web-форм.

      ' Не изменяйте его вручную в окне редактора кода.

      InitializeComponent()

     End Sub

    #End Region


     Dim Msg As String


     Private Sub Page_Load(ByVal sender As System.Object, _

      ByVal e As System.EventArgs) Handles MyBase.Load

      Button1.Text = "Check Date"

      TextBox1.Text = DateTime.Now.ToString

     End Sub


     Private Sub Button1_Click(ByVal sender As System.Object, _

      ByVal e As System.EventArgs) Handles Button1.Click

      Msg = IsDate(Request.Form.Item("TextBoxl")).ToString

      Msg += "<BR>"

      Msg += Request.Form.Item("TextBox1")

      If Page.IsPostBack Then

       Response.Write(Msg)

       Button1.Text = "Date Checked"

      End If

     End Sub

    End Class

    В листинге 12.1 нет никаких следов взаимодействия с клиентской частью.

    ЛИСТИНГ 12.2. Код самой Web-формы datecheck.aspx

    <%@ Page Language="vb" AutoEventWireup="false" Codebehind="datecheck.aspx.vb" Inherits="Novelty1.datecheck" %>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

    <HTML>

     <HEAD>

      <title>datecheck</title>

      <meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0">

      <meta name="CODE_LANGUAGE" content="Visual.Basic 7.0">

      <meta name="vs_defaultClientScript" content="JavaScript">

      <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">

     </HEAD>

     <body MS_POSITIONING="GridLayout">

      <form id="Form1" method="post" runat="server">

       <asp:TextBox id="TextBox1" style="Z-INDEX:101; LEFT: 10рх; POSITION: absolute; TOP: 36рх" runat="server" Width="165px" Height="20px">

       </asp:TextBox>

       <asp:Button id="Button1" style="Z-INDEX: 102; LEFT: 14px; POSITION: absolute; TOP: 73px" runat="server" Width="104px" Height="25px" Text="Button">

       </asp:Button>

      </form>

     </body>

    </HTML>

    В листинге 12.2 элементы управления формы содержат директиву runat=server, которая указывает на выполнение сервером действий, определенных во вспомогательном коде datecheck.aspx.vb. В листинге 12.3 приведен фактически генерируемый HTML-код, который передается клиенту. Код серверного элемента управления никогда не передается клиенту. Клиент получает только HTML-результат выполнения сервером кода данного элемента управления.

    ЛИСТИНГ 12.3. HTML-код клиента

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

    <HTML>

     <HEAD>

      <title>datecheck</title>

      <meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0">

      <meta name="CODE_LANGUAGE" content="Visual Basic 7.0">

      <meta name="vs_defaultClientScript" content="JavaScript">

      <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">

     </HEAD>

     <body MS_POSITIONING="GridLayout">

      <form name="Form1" method="post" action="datecheck.aspx" id="Form1">

      <input type="hidden" name="_VIEWSTATE" value="dDwxNDg50Tk5MzM7dDw7bDxpPDE+Oz47bDxOPDtsPGk8Mz47PjtsPHQ8cDxwPGw8VGV4dDs+02w8Q2hlY2sgRGFOZTs+Pjs+Ozs+Oz4+Oz4+Oz6QlVh6gd6Gbr95VzOdnBWPTkj/8w==" />

       <input name="TextBox1" type="text" value="17.06.2003 7:47:24" id="TextBox1" style="height:20px; width:165px; Z-INDEX:101; LEFT:10рх; POSITION: absolute; TOP:36px" />

       <input type="submit" name="Button1" value="Check Date" id="Button1" style="height:25px; width:104px; Z-INDEX: 102; LEFT: 14px; POSITION: absolute; TOP: 73px" /> 

      </form>

     </body>

    </HTML>

    В листинге 12.3 демонстрируется, что практически любая прикладная логика может быть сохранена на промежуточном уровне. В следующем разделе описываются способы работы с базой данных с помощью промежуточного уровня. Учтите, что подключение к базе данных и выполнение запроса организованы сложнее, чем проверка введенных данных.

    Обработка данных на промежуточном уровне

    До сих пор презентационный уровень описывался как визуальное представление приложения для клиента, а промежуточный уровень — как связующее звено (plumbing) между клиентом и основной частью приложения. Теперь пришло время показать роль окончательного уровня n-уровневой технологии, т.е. уровень данных. Обычно уровень данных состоит из базы данных, которая может иметь традиционную реляционную структуру, формат XML или формат файла INI. Далее в примерах этой главы в качестве хранилища данных используется SQL Server 2000.

    В листинге 11.1 из главы 11, "Web-формы: приложения на основе ASP.NET для работы с базами данных", показан простой пример использования промежуточного уровня для подключения к базе данных, выполнения запроса и возвращения объекта в виде HTML-таблицы. Этот код никак не влияет на возвращаемые данные, а только отображает их. На самом деле запрос выполняется в базе данных. В листинге 12.4 повторяется код подпрограммы ShowCustomers из листинга 11.5, который в следующем примере используется в другом контексте.

    ЛИСТИНГ 12.4. Код подпрограммы ShowCustomers

    Private Sub ShowCustomers()

     ' Это простой пример использования функции,

     ' которая извлекает данные из таблицы tblCustomer

     ' и отображает их.

     ' Инициализация объекта подключения строкой

     ' подключения.

     Dim conn As New SqlConnection (connString)

     ' Затем инициализация объекта-команды

     ' строкой выполняемой команды SQL.

     Dim cmd As New SqlCommand("exec sp_GetCustomersOrders", conn)

     conn.Open()

     Dim dReader As SqlDataReader = _

      cmd.ExecuteReader(CommandBehavior.CloseConnection)

     While dReader.Read

      Response.Write(dReader.GetString(0))

      Response.Write(" " & dReader.GetString(1))

      Response.Write(" "& dReader.GetDateTime(2))

      Response.Write("<BR>")

     End While

     dReader.Close()

     conn.Close ()

    End Sub

    Обратите внимание на использование хранимой процедуры sp_GetCustomeOrders, которая является типичным примером размещения прикладной логики на уровне данных приложения. Это сделано просто потому, что кратчайшее расстояние между двумя точками определяется прямой линией. Код, расположенный на сервере баз данных, компилируется для наиболее эффективного выполнения сервером. Поэтому в результате хранимая процедура, которая располагается на уровне данных, будет выполнена быстрее, чем хранимая процедура, которая располагается на промежуточном уровне.

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

    Создание повторно используемых компонентов промежуточного уровня

    В этом разделе описано создание простого запроса в виде повторно используемого объекта. Основная цель данного примера — продемонстрировать способ создания функции в одном месте и использования ее сразу в нескольких приложениях. Создайте новый или откройте уже имеющийся проект Visual Basic .NET. Щелкните правой кнопкой мыши на имени проекта в окне Solution Explorer и выберите в контекстном меню команду Add→Add Component. В диалоговом окне Add New Item в текстовом поле Name введите имя нового компонента GetRowCount.vb.

    НА ЗАМЕТКУ

    Коды всех примеров в этой и предыдущей главах основаны на решении Novelty1. Пространство имен Novelty1 используется в остальных примерах данной главы.

    После создания пустого компонента нужно включить в него код функции GetRowCount, которая возвращает целочисленное значение с количеством записей в таблице tblCustomers базы данных Novelty. В листинге 12.5 приведен полный код этого компонента.

    ЛИСТИНГ 12.5. Код компонента GetRowCount.vb

    Imports System.Data

    Imports System.Data.SqlClient


    Public Class GetRowCount

     Inherits System.ComponentModel.Component


     Public Function GetRowCount() As Integer

      Try

       Dim connString As String

       ' Помните обсуждение в главе 11 функции

       ' String.Intern? Если в памяти уже есть строка

       ' с тем же значением, то вместо создания нового

       ' экземпляра будет использована ссылка на нее.

       connString = _

        "server=(local);database=Novelty;TRUSTED_CONNECTION=Yes"

       Dim conn As New SqlConnection(connString)

       Dim cmd As New SqlCommand("select count(*) from tblCustomer", conn)

       conn.Open() Dim dReader As SqlDataReader = _

        cmd.ExecuteReader(CommandBehavior.CloseConnection)

       While dReader.Read

        ' Включить первую и единственную запись

        ' в результирующий набор.

        GetRowCount = dReader.GetValue(0)

       End While

       dReader.Close()

       conn.Close()

      Catch

       System.Console.WriteLine("An error has occurred " & Err.Description)

      End Try

     End Function


    #Region " Component Designer generated code "

     Public Sub New(ByVal Container As System.ComponentModel.IContainer)

      MyClass.New()

      ' Код, созданный конструктором компонентов.

      Container.Add(Me)

     End Sub


     Public Sub New()

      MyBase.New()

      ' Вызов метода, созданный конструктором компонентов.

      InitializeComponent()

      ' Инициализация после вызова метода

      InitializeComponent().

     End Sub


     ' Переопределение метода Dispose для очистки списка компонентов.

     Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

      If disposing Then

       If Not (components Is Nothing) Then

        components.Dispose()

       End If

      End If

      MyBase.Dispose(disposing)

     End Sub


     ' Код, созданный конструктором компонентов.

     Private components As System.ComponentModel.IContainer

      ' ЗАМЕЧАНИЕ: Код, созданный конструктором компонентов.

      ' Его можно изменять только с помощью конструктора компонентов

      ' Не изменяйте его вручную в окне редактирования кода.

      <System.Diagnostics.DebuggerStepThrough()> _

       Private Sub InitializeComponent()

       components = New System.ComponentModel.Container()

      End Sub

    #End Region

    End Class

    Более глубокое изучение иерархии наследования используемых компонентов выходит за рамки данной поэтому далее описывается лишь простой пример ее использования. Хотя в данном коде метод ToString не используется, но он применяется после компиляции вспомогательного кода. Для его применения нужно вставить в код строку Inherits System.ComponentModel.Component, которая позволяет использовать функции класса System.ComponentModel.Component, унаследованные от класса System.Object. Это наследование позволяет использовать функции данного класса без выполнения дополнительных действий.

    Для компоновки нового компонента щелкните на его имени в окне Solution Explorer правой кнопкой мыши и выберите в контекстном меню команду Build. Теперь готовый компонент можно использовать, но как? Создайте Web-форму GetRowCountTest.aspx со вспомогательным кодом, который показан в листинге 12.6. Обратите внимание, что в самом начале кода используется строка импорта компонента Novelty1.GetRowCount с функциями компонента GetRowCount.

    ЛИСТИНГ 12.6. Вспомогательный код GetRowCountTest.aspx.vb

    Imports Novelty1.GetRowCount


    Public Class GetRowCountTest Inherits System.Web.UI.Page


    #Region " Web Form Designer Generated Code "

     ' Вызов метода, созданный конструктором компонентов.

     <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

     End Sub


     Private Sub Page_Init(ByVal sender As System.Object, _

      ByVal e As System.EventArgs) Handles MyBase.Init

      ' CODEGEN: Этот вызов метода организован конструктором Web-форм.

      ' Не изменяйте его вручную в окне редактора кода. InitializeComponent()

     End Sub

    #End Region


     Private Sub Page_Load(ByVal sender As System.Object, _

      ByVal e As System.EventArgs) Handles MyBase.Load

      Dim GRC As New GetRowCount()

      Response.Write(GRC.GetRowCount.ToString)

      GRC.Dispose()

     End Sub

    End Class

    Здесь совсем не обязательно вызывать метод Dispose, предназначенный для очистки памяти от уже не нужного объекта. Создав данную страницу и вставив в нее код, щелкните правой кнопкой мыши на ее имени в окне Solution Explorer и выберите в контекстном меню команду Build and Browse. После выполнения всех созданных сценариев и доступа к базе данных Novelty будет отображена Web-страница с числом 2000.

    Использование компонента в другом приложении

    Попробуем теперь использовать созданный компонент в совершенно другом приложении. Для этого нужно создать новое приложение Visual Basic .NET на основе шаблона Windows Application среды Visual Studio .NET и создать в нем ссылку на файл Novelty1.dll, который располагается в каталоге bin проекта Novelty1. При использовании компонента из другого пространства имен или другого проекта нужно помнить, что dll-файл компонента находится в каталоге bin своего проекта. Например, dll-файл Web-приложения с именем Web_приложение обычно находится в каталоге с:\inetpub\wwwroot\Web_приложение\bin.

    Для указания ссылки на внешний компонент щелкните правой кнопкой мыши на элементе References в окне Solution Explorer и выберите в контекстном меню команду Add Reference. В диалоговом окне References щелкните на кнопке Browse и укажите dll-файл используемого компонента. Для закрытия диалогового окна References щелкните на кнопке OK. В данном примере предполагается, что dll-файл используемого компонента Novelty1.dll находится в каталоге c:\inetpub\wwwroot\ Novelty1\bin.

    Здесь следует напомнить, что, как и при работе с прежним приложением Windows, после указания директивы Imports его пространство имен становится полностью доступным. В общем вспомогательный код Web-формы из листинга 12.7 напоминает код из листинга 12.6. Он создан на основе шаблонного кода, сгенерированного конструктором Web-форм среды Visual Studio .NET.

    Листинг 12.7. Вспомогательный код Web-формы Form1.vb

    Imports Novelty1.GetRowCount


    Public Class Form1

     Inherits System.Windows.Forms.Form


    #Region " Windows Form Designer generated code "

     Public Sub New() MyBase.New()

      ' Этот вызов метода организован конструктором Web-форм.

      InitializeComponent()

      ' Инициализация после вызова метода InitializeComponent().

     End Sub


     ' Переопределение метода Dispose для очистки списка компонентов.

     Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

      If disposing Then

       If Not (components Is Nothing) Then

        components.Dispose()

       End If

      End If

      MyBase.Dispose(disposing)

     End Sub


     ' Код, созданный конструктором Web-форм.

     Private components As System.ComponentModel.IContainer

     ' ЗАМЕЧАНИЕ: Код, созданный конструктором компонентов.

     ' Его можно изменять только с помощью конструктора

     ' Не изменяйте его вручную в окне редактирования кода.

     Friend WithEvents Label1 As System.Windows.Forms.Label

     Friend WithEvents Button1 As System.Windows.Forms.Button

     <System.Diagnostics.DebuggerStepThrough()> _

      Private Sub InitializeComponent()

      Me.Label1 = New System.Windows.Forms.Label()

      Me.Button1 = New System.Windows.Forms.Button()

      Me.SuspendLayout()

      '

      ' Label1

      '

      Me.Label1.Location = New System.Drawing.Point(8, 16)

      Me.Label1.Name = "Label1"

      Me.Label1.Size = New System.Drawing.Size(248, 16)

      Me.Label1.Tablndex = 0

      Me.Label1.Text = "Label1"

      '

      ' Button1

      '

      Me.Button1.Location = New System.Drawing.Point(264, 8)

      Me.Button1.Next = "Button1"

      Me.Button1.Size = New System.Drawing.Size(72, 24)

      Me.Button1.TabIndex = 1

      Me.Button1.Text = "Test It!"

      '

      ' Form1

      '

      Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)

      Me.ClientSize = New System.Drawing.Size(344, 54)

      Me.Controls.AddRange(New System.Windows.Forms.Control() _

       {Me.Button1, Me.Label1})

      Me.Name = "Form1"

      Me.Text = "Form1"

      Me.ResumeLayout(False)

     End Sub

    #End Region


     Private Sub Button1_Click(ByVal sender As System.Object, _

      ByVal е As System.EventArgs) Handles Button1.Click

      Dim GRC As New Novelty1.GetRowCount()

      Label1.Text = "There are " & GRC.GetRowCount.ToString _

       & " rows in the table."

      GRC.Dispose ()

     End Sub

    End Class

    В код, созданный конструктором форм, добавлены только объекты Label1 и Button1. Текст надписи будет задан только во время выполнения приложения. Теперь можно приступить к созданию Web-службы.

    Доступ к объектам с помощью Web-служб

    Итак, мы приступаем к работе на совершенно новом уровне, т.е. с использованием Web-служб. С самого начала Web-среда рассматривалась как способ передачи данных между двумя точками. Именно эта исходная концепция способствовала развитию и популяризации Web-среды. Однако она обладала несколькими ограничениями и только недавно консорциум World Wide Web Consortium (W3C) начал реализовывать стандарты технологии обмена данными. Реализация Web-служб на платформе .NET основана именно на этих стандартах и использует язык XML для идентификации и передачи данных.

    Допустим, что компания Jones Novelties, Incorporated решила предоставить другим компаниям быстрый доступ к своим данным без необходимости создания пользовательского интерфейса. Для решения этой задачи прекрасно подходят Web-службы.

    Прежде чем приступить к решению этой бизнес-ситуации, следует привести основные сведения о Web-службах. Читатели с опытом создания Web-служб могут пропустить остаток этого раздела без ущерба для понимания остального материала или освежить свои знания, бегло познакомившись с ним.

    По определению Web-службы – это объекты, которые обмениваются данными с помощью протоколов Internet, например HTTP. Причем для определения данных или набора выполняемых сервером инструкций используется XML. Эти инструкции также могут возвращать данные. Например, для включения нового пользователя с фамилией Doe и именем John в базу данных можно послать некому воображаемому Web-серверу www.someserver.com следующий запрос:

    http://www.someserver.com/sevices/dataserver.asmx?op=AddUserToDB&FName= John&LName=Doe

    В данном примере используется протокол HTTP и запрос GET для вызова службы dataserver, которая имеет функцию AddUserToDB с двумя параметрами – FName и LName. Было бы просто замечательно, если бы у нас был способ доступа к Web-службе и информирования о выполняемых действиях. К счастью, Microsoft вместе с несколькими другими компаниями предусмотрела эту возможность и создала язык определения Web-служб Web Services Description Language, или WSDL (эта аббревиатура произносится как английское словосочетание wiz-dull). WSDL способен анализировать код Web-службы и находить ту информацию, которую нужно сообщить пользователям (людям или машинам) о данной Web-службе и выполняемых ею функциях. Пример такой функции приводится далее, в разделе о программном способе доступа к Web-службе. 

    Как уже отмечалось, доступ к Web-службе осуществляется с помощью HTTP-протокола (методы GET и POST). Основное различие между ними заключается в том, что при использовании GET параметры запроса передаются в URL-указателе, а при использовании POST – инкапсулируются внутри самого запроса.

    Кроме того, для взаимодействия Web-служб разработан протокол объектного доступа Simple Object Access Protocol (SOAP), который позволяет Web-серверам обмениваться сообщениями с инструкциями запросов, заключенными в конверт (envelope). SOAP-конверт имеет формат XML, как показано в приведенном ниже примере.

    <?xml version="1.0" encoding"utf-8"?>

    <soap:Envelope xmlns:xsi="http://www.w3c.org/2001/XMLSchema-insatance" xmlns:xsd="http://www.w3c.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

     <soap:Body>

      <ShowGetRowCountResponse xmlns="http://localhost/">

       <ShowGetRowCountResult>int</ShowGetRowCountResult>

      </ShowGetRowCountResponse>

     </soap:Body>

    </soap:Envelope>

    Для передачи такого запроса необходимо создать собственный Web-запрос и послать его серверу. К счастью, на платформе .NET в пространстве имен System.NET для выполнения этих действий предусмотрены специальные средства, которые существенно упрощают выполнение этой задачи.

    Рассмотрим бизнес-ситуацию, для решения которой следовало бы применить Web-службы.

    База данных содержит имена 100 тыс. человек в возрасте от 14 лет до 21 года. Вместе с этими данными хранятся постоянно обновляемые ответы посетителей Web-узла на ежедневно обновляемые вопросы. Допустим, что компания Pepsi хочет регулярно знакомиться с результатами таких опросов, например за 1 млн долларов в месяц. Как предоставить ей доступ к вашей базе данных? Именно в такой ситуации пригодятся Web-службы.

    Приведем еще один сценарий.

    Допустим, что некий Web-узел выполняет аутентификацию входа на другие Web-узлы, которые платят ежемесячную абонентную плату и предоставляют пароль и учетное имя для создания cookie-файлов на клиентских компьютерах с обозначением аутентификации пользователей. Похоже на службу Microsoft Passport, не так ли? В этой ситуации также пригодятся Web-службы.

    Web-службы дают разработчику возможность публиковать свои функции в Web-среде (Internet) или корпоративной среде (intranet), которые входят в состав других приложений или баз данных и располагаются на том же или на другом компьютере, о которых разработчик может даже не подозревать. Web-службы, по сути, стали именно тем, для чего разрабатывались COM-компоненты, но Web-службы можно вызывать с любого компьютера, подключенного к Internet или внутренней сети под управлением любой операционной системы.

    Итак, продолжим работу с нашим компонентом и включим в него дополнительную внешнюю функцию.

    Публикация существующего компонента с помощью Web-службы

    В большинстве случаев для публикации функций существующего компонента с помощью Web-службы достаточно поместить соответствующий код в Web-службе в виде открытого метода с возвращаемым значением. Например, для публикации с помощью Web-службы метода GetRowCount класса GetRowCount из предыдущего примера выполните перечисленные ниже действия.

    1. В проекте Novelty1 создайте новую Web-службу NoveltyServices.asmx.

    НА ЗАМЕТКУ

    Для работы с компонентом из другого пространства имен следует создать ссылку на него, как описывается выше в главе, в разделе об использовании компонента из другого приложения.

    2. В файле NoveltyServices.asmx вставьте код нового Web-метода ShowGetRowCount, который приведен в листинге 12.8.

    3. Добавьте в тело метода ShowGetRowCount три строки кода, как показано в листинге 12.8.

    4. Щелкните правой кнопкой мыши на имени решения в окне Solution Explorer и выберите в контекстном меню команду Build для компоновки решения.

    5. После компоновки решения щелкните правой кнопкой мыши на файле NoveltyServices.asmx и выберите в контекстном меню команду View in Browser (Просмотр в окне Web-броузера).

    6. Сразу после загрузки Web-страницы полученной Web-службы NoveltyServices щелкните на гипертекстовой ссылке ShowGetRowCount в верхней части Web-страницы.

    7. Убедитесь в правильности полученных результатов. (Сначала в окне Web-броузера появится описание данной Web-службы с предложением проверить ее работоспособность, щелкнув на кнопке Invoke (Вызвать Web-службу). Щелкните на этой кнопке, и в окне Web-броузера появится XML-файл с приведенными ниже строками.

    <?xml version="1.0" encoding="utf-8"?>

    <int xmlns="http://localhost/">2000</int>

    Здесь значение 2000 типа int – это результат выполнения метода ShowGetRowCount Web-службы NoveltyServices. — Прим. ред.)

    ЛИСТИНГ 12.8. Файл NoveltyServices.asmx

    Imports System.Web.Services

    Imports Novelty1.GetRowCount


    <WebService(Namespace:="http://localhost/")> _

     Public Class NoveltyServices

     Inherits System.Web.Services.WebService


    #Region " Web Services Designer Generated Code "

     Public Sub New()

      MyBase.New()

      ' Этот вызов метода организован конструктором Web-служб.

      InitializeComponent()

      ' Инициализация после вызова метода

      InitializeComponent().

     End Sub


     ' Код, созданный конструктором Web-служб.

     Private components As System.ComponentModel.IContainer


     ' ЗАМЕЧАНИЕ: Код, созданный конструктором компонентов.

     ' Его можно изменить только с помощью конструктора Web-служб.

     ' Не изменяйте его вручную в окне редактирования кода.

     <System.Diagnostics.DebuggerStepThrough()> _

      Private Sub InitializeComponent()

      components = New System.ComponentModel.Container()

     End Sub


     Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

      ' CODEGEN: Этот вызов метода организован конструктором Web-служб.

      ' Не изменяйте его вручную в окне редактора кода.

      If disposing Then

       If Not (components Is Nothing) Then

        components.Dispose()

       End If

      End If

      MyBase.Dispose(disposing)

     End Sub

    #End Region


     <WebMethod()> Public Function ShowGetRowCount() As Integer

      ' Эти строки кода остались неизменными.

      Dim GRC As New GetRowCount()

      ShowGetRowCount = GRC.GetRowCount GRC.Dispose()

     End Function

    End Class

    Вот и все. Теперь после размещения этого кода на открытом Web-сервере любой пользователь может с помощью Web-броузера открыть данную Web-страницу и выполнить указанный метод. Обычно эта цель достигается программными средствами, а не вручную. В следующем разделе рассматривается пример такой ситуации.

    Доступ к Web-службе программными средствами

    Попробуем теперь использовать созданную Web-службу программными средствами из другого приложения, будь то обычное приложение Windows или Web-приложение.

    Для соединения с Web-службой нужно создать Web-ссылку. Для создания такого соединения можно послать простой GET-запрос на основе протокола HTTP, который обычно заканчивается вопросительным знаком (?) с параметрами, разделенными амперсандами (&), например: http://search.yahoo.com/bin/search?p=VB.Net&VS.Net.

    Кроме того, для создания соединения можно послать простой POST-запрос на основе протокола HTTP, параметры которого передаются в HTTP-заголовках. Еще один способ основан на применении протокола SOAP, благодаря которому Web-серверу посылается специализированный XML-файл, а Web-служба, в свою очередь, возвращает специализированный XML-файл в контейнере, заданном в SOAP-запросе.

    Рис. 12.1. Диалоговое окно Add Web Reference  

    Для демонстрации программного доступа к Web-службе создайте проект нового консольного приложения Visual Basic .NET на основе шаблона Console Application среды Visual Studi o.NET. Учтите, что основные принципы доступа к Web-службе остаются одинаковыми независимо от типа проекта. После создания проекта щелкните правой кнопкой мыши на элементе References в окне Solution Explorer и в контекстном меню выберите команду Add Web Reference (Создать Web-ссылку). На экране появится диалоговое окно Add Web Reference (рис. 12.1). Укажите в текстовом поле Address (Адрес) URL-указатель используемой Web-службы и нажмите клавишу <Enter>. После этого в правой части диалогового окна Add Web Reference сразу же появится описание Web-службы NoveltyServices (см. рис. 12.1). Такой результат получается благодаря языку WSDL, который вставляет метаданные с описанием Web-службы в ее код. Щелкните на кнопке Add Reference для закрытия данного диалогового окна и вставки созданной ссылки в проект консольного приложения. В окне Solution Explorer теперь появится новая Web-ссылка, аналогичная показанной на рис. 12.2.

    РИС. 12.2. Новая Web-ссылка в окне Solution Explorer


    НА ЗАМЕТКУ

    Если доступа каталогу или Web-серверу нужно пройти аутентификацию, то код нужно разместить в приложении, а не в Web-службе.

    Теперь, после создания Web-ссылки, остается только включить в код консольного приложения три строки, которые показаны в листинге 12.9 с полным кодом основного модуля Module1.vb консольного приложения ConsoleApplication1.

    ЛИСТИНГ 12.9. Код основного модуля Module1.vb

    Module Module1

     Sub Main()

      Dim GRC As New localhost.NoveltyServices()

      Try

       System.Console.WriteLine(GRC.ShowGetRowCount.ToString)

       GRC.Dispose()

      Catch

       System.Console.WriteLine(Err.Description)

      End Try

     End Sub

    End Module

    Здесь объект GRC обозначает Web-службу localhost.NoveltyServices(). Дело в том, что в данном примере используется локальный Web-сервер localhost, который в листинге 12.8 играет роль пространства имен для данной Web-службы. Учтите, что пространства имен должны иметь уникальные имена (например, название вашей компании) или полностью квалифицированное имя домена, на котором располагаются ваши Web-службы. Например, сотрудники компании Microsoft могут использовать в качестве имени для пространства имен адрес www.microsoft.com. Тогда объявление нового объекта objectname в данном пространстве имен будет иметь следующий вид:

    new www.microsoft.com.objectname

    После вставки дополнительных строк кода в основной модуль Module1.vb и указания Web-ссылки на Web-службу можно скомпоновать все решение. Для этого щелкните правой кнопкой мыши на имени решения в окне Solution Explorer и выберите в контекстном меню команду Build Solution. Для запуска полученного приложения откройте консольное окно Windows и в режиме командной строки укажите каталог проектов VS.NET, который по умолчанию имеет вид

    C:\Documents and Settings\<имя_лользователя>\Му Documents\Visual Studio Projects

    Далее найдите в основном каталоге этого консольного приложения (т.е. в каталоге ConsoleApplication1 в данном примере) его подчиненный каталог bin. В нем содержится выполняемый файл проекта ConsoleApplication1.exe. Введите в командной строке путь к нему, имя, а затем нажмите клавишу <Enter>.

    C:\Documents and Settings\<имя_пользователя>\Му Documents\Visual Studio Projects\ConsoleApplication1\bin\ConsoleApplication1.exe

    Спустя несколько секунд в командной строке появится результат выполнения консольного приложения и вызванной им Web-службы, а именно: количество записей в таблице tblCustomer базы данных Novelty.

    Заключительные замечания

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

    С самого начала книги, где рассматривались этапы планирования и создания базы данных, и до последних страниц, где описываются способы расширения функциональности приложения за счет повторно используемого кода и Web-служб, авторы преследовали одну и туже цель, а именно: создать надежное приложение с помощью наиболее эффективных средств. Многие примеры из этой книги можно буквально скопировать и вставить в приложение, используя практически без всяких изменений (не считая строк запросов). Авторы уверены, что использование представленной информации позволит читателям успешно создавать и размещать приложения с помощью Visual Basic .NET и SQL Server на основе традиционной технологии клиент/сервер ("толстый" клиент + Windows-формы) или Web-ориентированной технологии ("тонкий" клиент + Web-формы).

    Резюме

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

    Вопросы и ответы

    Можно ли вызывать Web-службы из языка Java?

    Да. В языке программирования Java предусмотрена библиотека классов java.net, предназначенная для подключения к Web-службе (по заданному URL-указателю посредством протокола HTTP), которая работает на платформе .NET. Для синтаксического анализа полученного результата в языке программирования Java применяются специализированные классы для работы с XML-файлами.

    Как опубликовать Web-службу через брандмауэр?

    Web-службы обычно доступны через порт 80 (который используется для HTTP), поэтому, с точки зрения системного администратора, для них нет никаких ограничений. На самом низком уровне Web-служба — это не что иное, как Web-страница без графического интерфейса пользователя. Что касается программного доступа, то, конечно, можно создать несколько методов аутентификации доступа на Web-сервер.








    Главная | В избранное | Наш E-MAIL | Прислать материал | Нашёл ошибку | Наверх