Статья: Web Services и MS Visual FoxPro Часть 6

В этой статье :

  • Всё тот же Web Service, но уже в ASP.NET.
  • FAQ.
  •  

    Всё тот же Web Service, но уже в ASP.NET.
    Может быть, Вы уже слышали эту плохую новость, но Microsoft отказался от поддержки своего пакета SOAP 3.0. Он пока еще работает и даже вошел в комплект поставки VFP 9.0, но будущего у него нет. А что же взамен? Прежде всего MS рекомендует ASP.NET. Возможно использование SOAP пакетов других фирм, например, Rick Strahl's West Wind Technologies. Или даже classic ASP.
    На наш взгляд самый простой вариант - ASP.NET (VB.NET) (у нас ушло всего пару часов для этого). Воспользуемся услугами VS.NET 2003.
    1. Создадим в IIS виртуальный директорий для нашего будущего проекта:
    Виртуальный директорий для Web Service.
    2. Откроем VS.NET 2003, из меню нового проекта выберем
    Окно VS.NET 2003 для создания Web Service.
    3. Построитель быстро создаст для нас несколько файлов. В настоящий момент нас интересует только два. Первый из них - это непосредственно Web Service.
    Окно VS.NET 2003 для создания Web Service - нам надо выбрать режим внесения кода.
    4. Переключимся в режим просмотра кода. Без сожаления удаляем весь код, который для нас создал построитель (в будущем Вы можете  изучить это код как пример создания Web Service). Вносим наш простой код:
    Imports System
    Imports System.Data
    Imports System.Web.Services
    Imports System.Data.OleDb
    
    <System.Web.Services.WebService(Namespace:="http://tempuri.org/ws_net/Service1")> _
    Public Class Service1
        Inherits System.Web.Services.WebService
    
        <WebMethod(Description:="Standard login operation.")> _
        Public Function login(ByVal lclog As String, ByVal lcpsw As String) As String
              Dim myConnString As String
              myConnString = System.Configuration.ConfigurationSettings.AppSettings("ws_net_String")
              Dim conSessionID As OleDbConnection = New OleDbConnection(myConnString)
              Dim paramReturnValue As OleDbParameter
              Dim cmdSessionID As OleDbCommand = New OleDbCommand _
              ("sp_user_login_xml('" + Trim(lclog) + "','" + Trim(lcpsw) + "')", conSessionID)
              conSessionID.Open()
              Dim strreturn As String = cmdSessionID.ExecuteScalar()
              conSessionID.Close()
              Return strreturn
        End Function
    
        <WebMethod(Description:="Some operations for message program.")> _
        Public Function message_read(ByVal lckey_word As String, ByVal lcUser_nick As String, _
          ByVal lcpassword As String, ByVal lcparameter1 As Object, ByVal lcparameter2 As Object, _
          ByVal lcparameter3 As Object, ByVal lcparameter4 As Object, _
          ByVal lcparameter5 As Object, ByVal lcparameter6 As Object) As Object
              Dim myConnString As String
              myConnString = System.Configuration.ConfigurationSettings.AppSettings("ws_net_String")
              Dim conSessionID As OleDbConnection = New OleDbConnection(myConnString)
              Dim paramReturnValue As OleDbParameter
              Dim strreturn As Object
              Dim cmd As OleDbCommand
              strreturn = -1
              Select Case lckey_word
                Case "READ_MESSAGES_START"
                 cmd = New OleDbCommand("sp_message_read", conSessionID)
                 cmd.CommandType = CommandType.StoredProcedure
                 cmd.Parameters.Add("@lcparameter1", OleDbType.Date).Value = lcparameter1
                 cmd.Parameters.Add("@lcUser_nick", OleDbType.VarChar, 10).Value = lcUser_nick
                 cmd.Parameters.Add("@lcpassword", OleDbType.VarChar, 10).Value = lcpassword
                 cmd.Parameters.Add("@lcparameter2", OleDbType.Integer).Value = lcparameter2
               Case "READ_ALL_USERS"
                 cmd = New OleDbCommand("sp_users_read_xml", conSessionID)
                 cmd.CommandType = CommandType.StoredProcedure
                 cmd.Parameters.Add("@lcUser_nick", OleDbType.VarChar, 10).Value = lcUser_nick
                 cmd.Parameters.Add("@lcpassword", OleDbType.VarChar, 10).Value = lcpassword
               Case "ADD_NEW_MESSAGE"
                 cmd = New OleDbCommand("sp_new_message_add", conSessionID)
                 cmd.CommandType = CommandType.StoredProcedure
                 cmd.Parameters.Add("@lcUser_nick", OleDbType.VarChar, 10).Value = lcUser_nick
                 cmd.Parameters.Add("@lcpassword", OleDbType.VarChar, 10).Value = lcpassword
                 cmd.Parameters.Add("@lcparameter1", OleDbType.Integer).Value = lcparameter1
                 cmd.Parameters.Add("@lcparameter2", OleDbType.VarChar, 100).Value = lcparameter2
                 cmd.Parameters.Add("@lcparameter3", OleDbType.LongVarChar).Value = lcparameter3
               Case "READ_THREAD_START"
                 cmd = New OleDbCommand("sp_thread_read", conSessionID)
                 cmd.CommandType = CommandType.StoredProcedure
                 cmd.Parameters.Add("@lcUser_nick", OleDbType.VarChar, 10).Value = lcUser_nick
                 cmd.Parameters.Add("@lcpassword", OleDbType.VarChar, 10).Value = lcpassword
                 cmd.Parameters.Add("@lcparameter1", OleDbType.Integer).Value = lcparameter1
               Case "ADD_EXISTS_MESSAGE"
                 cmd = New OleDbCommand("sp_existed_message_add", conSessionID)
                 cmd.CommandType = CommandType.StoredProcedure
                 cmd.Parameters.Add("@lcUser_nick", OleDbType.VarChar, 10).Value = lcUser_nick
                 cmd.Parameters.Add("@lcpassword", OleDbType.VarChar, 10).Value = lcpassword
                 cmd.Parameters.Add("@lcparameter1", OleDbType.LongVarChar).Value = lcparameter1
                 cmd.Parameters.Add("@lcparameter1", OleDbType.Integer).Value = lcparameter2
               Case "DELETE_THREAD"
                 cmd = New OleDbCommand("sp_message_delete", conSessionID)
                 cmd.CommandType = CommandType.StoredProcedure
                 cmd.Parameters.Add("@lcUser_nick", OleDbType.VarChar, 10).Value = lcUser_nick
                 cmd.Parameters.Add("@lcpassword", OleDbType.VarChar, 10).Value = lcpassword
                 cmd.Parameters.Add("@lcparameter1", OleDbType.Integer).Value = lcparameter1
               Case "DELETE_ANSWER"
                 cmd = New OleDbCommand("sp_answer_delete", conSessionID)
                 cmd.CommandType = CommandType.StoredProcedure
                 cmd.Parameters.Add("@lcUser_nick", OleDbType.VarChar, 10).Value = lcUser_nick
                 cmd.Parameters.Add("@lcpassword", OleDbType.VarChar, 10).Value = lcpassword
                 cmd.Parameters.Add("@lcparameter1", OleDbType.Integer).Value = lcparameter1
                 cmd.Parameters.Add("@lcparameter2", OleDbType.Integer).Value = lcparameter2
                Case "READ_PROFILE_USERS"
                 cmd = New OleDbCommand("sp_users_profile_read_xml", conSessionID)
                 cmd.CommandType = CommandType.StoredProcedure
                 cmd.Parameters.Add("@lcUser_nick", OleDbType.VarChar, 10).Value = lcUser_nick
                 cmd.Parameters.Add("@lcpassword", OleDbType.VarChar, 10).Value = lcpassword
                 cmd.Parameters.Add("@lcparameter1", OleDbType.Integer).Value = lcparameter1
                Case "ADD_NEW_USER"
                 cmd = New OleDbCommand("sp_users_add_edit", conSessionID)
                 cmd.CommandType = CommandType.StoredProcedure
                 cmd.Parameters.Add("@lcUser_nick", OleDbType.VarChar, 10).Value = lcUser_nick
                 cmd.Parameters.Add("@lcpassword", OleDbType.VarChar, 10).Value = lcpassword
                 cmd.Parameters.Add("@lcparameter1", OleDbType.Integer).Value = lcparameter1
                 cmd.Parameters.Add("@lcparameter2", OleDbType.LongVarChar).Value = lcparameter2
              End Select
              conSessionID.Open()
              strreturn = cmd.ExecuteScalar()
              conSessionID.Close()
              Return strreturn
        End Function
    End Class
    Предлагаемый Вашему вниманию код абслютно прозрачен. Вначале мы присоединяем все необходимые библиотеки для работы. Затем создаем класс Service1, в котором как и в оригинальном варианте будет два метода. Так как FoxPro довольно вольно относится к типам переменных, и чтобы нам не менять идеологию создаваемого Web Service, мы вынуждены применять тип Object для входных параметров . Далее строим OleDbCommand путем добавления необходимых параметров и точной их типизации. Как мы видим, все предельно просто, ибо новый язык VB.NET очень похож на VFP. 
    5. Изменим немного файл web.config (аналог config.fpw в VFP). Главное, это внесем строку для определения источника данных MS VFP OleDB Peovider:
    <!-- Web.Config Configuration File -->
    <configuration>
     <system.web>
      <customErrors mode="Off" />
      <compilation debug="true" />
      <httpRuntime maxRequestLength="8192" />
      <globalization requestEncoding="windows-1251" responseEncoding="windows-1251" 
      culture="ru-Ru" uiCulture="ru-Ru" />
      <authorization>
       <allow users="*" />
      </authorization>
     </system.web>
     <appSettings>
      <add key="ws_net_String" value="provider=vfpoledb.1;
      Data Source=C:\ws_message\server\DBWS.dbc;Mode=ReadWrite|Share Deny None;" />
     </appSettings>
    </configuration>
    6. Не забудем установить на Ваш Web Server MS VFP 9.0 OleDB Provider (который можно скачать бесплатно с сайта компании Microsoft).
    7. Выбираем в верхнем меню VS.NET - Buid -> Build Solution.
    8. Меняем в теле клиента имя Web Service: http://localhost/ws_net/Service1.asmx?WSDL
    9. Не забываем дать права на запись и чтение клиенту IIS и ASP.NET в директорий, где находится Ваша база данных VFP.
    10. В общем-то и все (имя реального Web Service для тестирования Вашего приложения находится по адресу: http://www.sergey.co.uk/WebModules/NewsManaer/ws_mes.asmx?WSDL )...
    Как мы видим, абсолютно ничего сложного. Разобравшись с данным примером, можно строить гораздо более сложные приложения.
    FAQ.
    Цикл статей "писался на лету" при большой помощи участников FoxPro сообщества. По мере публикации отдельныйх статей возникало большое количество вопросов, уточнений и замечаний. Многие из них нашли свое место непосредственно в статьях, часть из них была выделена в этот FAQ. Если Вы хотите внести Ваши замечания, то наиболее простой способ - написать об этом на местном форуме:  http://www.sergey.co.uk/WebModules/Forums/Forum.aspx?ForumId=3  . Так как информация об этих статьях была опубликована на разных форумах, у автора просто нет физической возможности просматривать их все. Заранее приносим свои извинения за причиненные неудобства.
    1. Могу ли я принимать информацию от Web Services, если в нашей корпоративной компьютерной сети установлена FireWall?

    Если коротко ответить - то "да". Дело в том, что Web Service использует протокол HTTP и порт 80 (как и Ваш Browser через который Вы просматриваете Web Sites в Internet). То есть теоретически проблем быть на должно. На практике есть нюансы. Если у Вас установлены, например, продукты компании Microsoft - Win Proxy, ISA 2000 или ISA 2003, то Вам необходимо установить на Ваш компьютер клиента, который идет в комплекте с этим программным обеспечением. Нельзя забывать и о том, что эти клиенты не совместимы между собой. То есть при установке ISA 2003 надо удалить предыдущую версию в ручную.

    Если Ваш сетевой администратор все правильно установил (что бывает, увы не всегда в силу довольно низкой их зарплаты и как следствие низкой квалификации с непомерными амбициями) Вы должны видеть сетевой каталог в котором находится программа для установки этого FireWall клиента на Вашей машине. Если этого нет, то спросите своего админа об этом. Если Вы единственный IT специалист в компании - то посмотрите на дистрибутиве или скачайте из Internet.

    Клиент ISA 2003 делает всю работу для Вас - там есть специальная кнопка "настроить Browser". Для предыдущих версий Вам необходимо прописать имя этого Proxy Server и указать его порт для внутренних рабочих станций (по умолчению 8080) плюс обходить Proxy для локальных адресов. То есть приблизительно вот такая картинка:

    Окно свойств Internet Browser.
    Еще возможная причина невозможности приема данных от внешних источников - это ограничения, накладываемые администратором Вашей сети. Очень часто они всё запрещают и разрешают только то, что сочтут нужным. Здесь решения уже выходять за рамки данной статьи. Как говорил один известный в детских кругах телегерой "Со всеми надо жить дружно".
    2. Что делать, если вместо символов национального алфавита я принимаю знаки вопросов?

    Это очень комплексный вопрос. Прежде всего на Вашем сервере и на рабочих станциях должен быть установлен Ваш национальный язык как основной. Если у Вас на сервере не установлена полная версия VFP на период эксплуатации - необходимо, чтобы рядом с Runtime Library VFP были библиотеки поддержки Вашего национального языка. Насчет файла config.fpw с явным указанием кодовой страницы - я не могу дать точного ответа на это вопрос, так-как WS вызывает COM Server на основе VFP и директорием по умолчанию для Windows 200 будет WINNT\System32 (для WINXP Windows\System32) и читает ли он config.fpw трудно сказать. В 7 версии VFP я столкнулся с тем, что пришлось в двоичном редакторе менять код внутри VFP Runtime Library, чтобы кодовой страницей по умолчанию стала 1251. Надеюсь, что в 9 версии этого делать не надо, так-как при тестировании все работало стабильно.

    3. Что надо установить на рабочих станциях моих клиентов для работы с Web Service?
    Прежде всего библиотеки поддержки VFP. Затем пакет MS SOAP 3.0, на некоторых устаревших версиях Windows возможно потребуется установка XML Parsel версии не ниже 3.
    4. Как сделать мой Web Service видимым для всего мира?
    Для этого надо его опубликовать на живом Web Server. При публикации listener URI будет выглядеть примерно так: http://www.yourserver.ru/web_service/  все остальные замечания по поводу конфигурации виртуального директория и прав доступа остаются примерно такими - же как и для примера на Вашей локальной машине.
    5. Как увеличить безопасность данных если к ним будет доступ через Intenet?
    Как заявляет сама компания Microsoft - создать безопасное приложение на основе Web Service невозможно. Возможно только постараться ограничить вероятность поврежедения Ваших данных злоумышленниками. Мой главный совет - шифровать все данные, передаваемые на Web Service. В принципе, программа шифрования несложная и если желающих будет много, то можно будет предлагаемый код опубликовать как еще одну статью.
    6. Нужен ли на клиентских машинах IIS и/или .NET Framework?
    Короткий ответ - "Нет". Описанная нами технология не использует их.