Архитектура веб-служб
Служба ASP.NET состоит из библиотеки DLL, файла ASMX и файла Codebehind, который содержит класс, специально созданный для работы с веб-службами. Файл ASMX аналогичен файлу ASPX веб-формы ASP.NET, через него выполняются запросы веб-служб. В данной лекции мы будет считать веб-службу и класс с интегрированным HTTP-интерфейсом равнозначными. В проект можно добавлять другие классы, при этом не нужно создавать другой файл ASMX, так как классы сами по себе не являются веб-службами. При добавлении класса создается только файл для поддержки кода класса с именем <имя_класса>.cs или <имя класса>.<расширение_языка>.
В проект веб-службы Visual Studio .NET может входить несколько веб-служб. При компиляции проекта результат записывается в одну библиотеку DLL. Она включает классы нескольких файлов ASMX и дополнений к классам, поддерживающим файлы веб-службы ASMX.
Файл ASMX связан в IIS с расширением ISAPI aspnet_isapi.dll, поэтому при запросе файла ASMX из IIS aspnet_isapi.dll направляет HTTP-запрос нужной DLL-библиотеке веб-службы (см. рис. 3.1). Файл ASMX связан в один момент времени с одной DLL-библиотекой. Как правило, проекты веб-служб Visual Studio .NET располагают DLL в каталоге двоичных файлов внутри папки с файлами ASMX.
Веб-службы ASP.NET используют те же файлы конфигурации библиотеки и файлы конфигурации реализации IIS, что и веб-формы ASP.NET. Файлы веб-службы ASP.NET, используемые компилятором для создания веб-службы в библиотеке, именуются <имя_веб-службы>.asmx (в отличие от файлов веб-форм ASP.NET с расширением .aspx). Веб-служба ASP.NET имеет ту же самую архитектуру, равно как и типы файлов, связанные с ней внутри проекта. Например, файл ASMX является адресуемой входной точкой веб-службы и как главный файл предоставляет директивы обработки для компиляции веб-службы. Файл ASMX описывает файлы, предназначенные для веб-службы ASP.NET, и сам может содержать в себе код. Код, связанный с веб-службой ASP.NET, обычно располагается в файле Codebehind. Файл Codebehind <моя_служба>.asmx.cs содержит исходный код веб-службы, а файл <моя_служба>.asmx.resx является источником, обслуживающим файл Codebehind.
Рис. 3.1. Обзор архитектуры веб-служб
Примечание. Файл ASMX может включать код вместо файла Codebehind, однако Visual Studio .NET использует файл Codebehind в шаблоне проекта веб-службы по умолчанию. Если файл ASMX не использует Codebehind, то технология .NET компилирует файл и создает DLL автоматически по первому запросу.
Безопасность приложения
Запись данных в журнал событий не требует модификации прав, под которыми работает веб-служба. Новыми возможностями IIS6 являются две встроенные учетные записи для рабочих процессов: Network Service (Сетевая служба) и Local Service (Локальная служба). В предыдущих версиях рабочие процессы для IIS выполнялись под учетной записью Local System (Локальная система). Учетная запись Network Service (Сетевая служба) является учетной записью по умолчанию для выполнения рабочих процессов в IIS. Она более ограничительна по сравнению с Local System (Локальная система), а учетная запись Local Service (Локальная службы) – более ограничительна по сравнению с Network Service (Сетевая служба). Можно создать особую учетную запись для обеспечения определенных требований к безопасности приложения.
Для настройки приложения на работу под другой учетной записью следует создать новый пул приложения и настроить его на работу под аутентификационными данными учетной записи Local System (Локальная система).
Откройте консоль MMC Computer Management (Управление компьютером) с помощью команды Start\Administrative Tools (Пуск\Администрирование).Откройте узел Internet Information Services (IIS) Manager (Диспетчер IIS), затем – узел папки Aplication Pools (Пулы приложения). В дереве, расположенном под папкой Application Pools (Пулы приложений), в виде значков отобразятся все пулы приложения. В списке должен присутствовать пул приложения DefaultAppPool. При его развертывании отобразятся веб-сайты, использующие этот элемент (см. рис. 3.12).Веб-сайт по умолчанию Default Web Site, созданный при установке IIS, использует пул DefaultAppPool. Как видно из рисунка 3.12, сайт Default Web Site присутствует в списке многих веб-приложений, использующих DefaultAppPool. Для настройки пула приложения откройте страницу свойств веб-сайта или виртуального каталога, щелкнув правой кнопкой мыши на узле и выбрав команду Properties (Свойства).
увеличить изображение
Рис. 3.12. Приложения, использующие DefaultAppPool, отображаются в консоли MMC Computer Management (Управление компьютером)
Откройте вкладку Home Directory (Домашний каталог) веб- сайта либо вкладку Virutal Directory (Виртуальный каталог) виртуального каталога. Во вкладке Home Directory (Домашний каталог) поле со списком Application Pool (Пул приложения) отображает доступные пулы приложения (см. рис. 3.13).
Рис. 3.13. Вкладка Home Directory (Домашний каталог) окна свойств веб-сайта по умолчанию
Веб-служба Events работает в виртуальном каталоге myPortal, расположенном на сайте Default Web Site. Виртуальный каталог myPortal настроен на использование пула DefaultAppPool, работающего под аутентификационными данными учетной записи Network Service (Сетевая служба). Когда веб-служба Events попытается записать данные в журнал событий, произойдет ошибка, так как учетная запись Network Service (Сетевая служба) не имеет соответствующих прав. В предыдущей версии IIS запись в журнал приложений веб-службой Events осуществляется без всяких проблем. Для разрешения проблемы доступа создайте новый пул приложения, использующий учетную запись Local System, и настройте myPortal на работу с новым пулом приложения.
Щелкните правой кнопкой мыши на значке Application Pools (Пулы приложений) в консоли Computer Management (Управление компьютером) и выберите New\Aplication Pool (Создать\Пул приложения).В диалоговом окне Add New Application Pool (Создание нового пула приложения) (см. рис. 3.14) видно, что идентификатор ID пула приложения равен значению webservice using LocalSystem. В нашем случае используются параметры по умолчанию нового пула приложения.
Рис. 3.14. Диалоговое окно Add New Application Pool (Создание нового пула приложения)
Нажмите на кнопку OK.
Ниже приведены шаги по смене объекта пула приложения webservice using LocalSystem.
Щелкнув правой кнопкой на вновь созданном узле webservice using LocalSystem в консоли MMC Computer Management (Управление компьютером) в узле Application Pools (Пулы приложения) и выберите пункт Properties (Свойства).В окне свойств откройте вкладку Identity (Объект) и в списке учетных записей Predefined security account (Предопределенные учетные записи безопасности) выберите Local System (Локальная система) (см.
рис. 3.15).
Рис. 3.15. Настройка учетной записи для пула приложения
Нажмите на кнопку OK или на кнопку Apply (Применить). Появится окно с предупреждением об опасностях, связанных с работой пула приложений в учетной записи Local System (Локальная система). Вы можете настроить учетную запись в соответствии с требованиями безопасности, чтобы веб-служба осуществляла запись в журнал событий приложения.
После создания пула приложения виртуальный каталог myPortal нужно настроить на использование пула приложения webservice using LocalSystem. Откройте окно свойств для myPortal и во вкладке Directory (Каталог) выберите новый пул приложения (см. рис. 3.16).
Рис. 3.16. Выбор нового пула приложения webservice using LocalSystem для myPortal
Фиксирование данных о состоянии и ошибок в журнале
Во всех веб-службах на локальном сервере должны фиксироваться данные о состоянии и ошибках. Довольно часто в веб-проектах не предусматривается адекватная система обработки ошибок или предоставление диагностической информации о том, какие действия выполняются в коде. Если в приложении возникают ошибки, а ошибочное условие нельзя продублировать в среде разработки, то выход из положения – разрешить разработчику доступ к среде разработки для диагностирования и отладки кода. Приложение не должно диагностироваться в среде разработки. Поскольку разработчики могут просматривать сообщения, записанные в журнал приложения, и использовать простые методы записи информации в журнал Application, нет причин для выполнения подобных действий при диагностике ошибки. Разрешение доступа к среде разработки является большой ошибкой приложения, и ее легко избежать, обеспечив надежную систему обработки ошибок и ведение журналов диагностики.
Класс Data Reader
С учетом псевдонимов, сгенерированных дизайнером компонентов, можно разработать код, устанавливающий параметры и заполняющий объект DataReader. Например, функция Add веб-службы Events использует экземпляр класса команды InsertEvent для добавления нового события. Псевдонимы имен полей таблицы базы данных, определенные при инициализации класса InsertEvent, используются методом Parameters для присвоения значения полю, представляемому псевдонимом в команде Insert SQL, используемой классом InsertEvent для обновления таблицы базы данных. В листинге 3.7 приведен код функции Add.
Листинг 3.7. Add Function in Events Web Service (html, txt)
Экземпляр класса SQLDataReader создан для доступа к данным, возвращаемым из экземпляра класса SQLCommand с именем InsertEvent. Экземпляр InsertEvent установлен в качестве свойства объекта SQLDataAdaptor EventsAdaptor и имеет объект подключения servicesDBConn, поэтому он возвращает данные экземпляру объекта SQLDataReader с именем myEvent. Локальный экземпляр anEvent с именем mEvent используется для хранения текущего состояния события веб-службы Events. В листинге 3.8
приведен исходный код класса anEvent.
Листинг 3.8. Source Code for Class anEvent (html, txt)
Как видно из листинга 3.8, класс anEvent содержит данные, формирующие событие Event. Веб-служба Events считывает и записывает значения события в источник базы данных, поэтому для класса Events объявлен и создан локальный экземпляр anEvent.
Когда функция Add (см. листинг 3.7) устанавливает параметры для Name, Date и Description, она берет соответствующие значения свойств для экземпляра mEvent класса anEvents. Свойства mEvent устанавливаются в веб-службе Events потребителем или извлекаются из базы данных для Event, загружаемой в веб-службу. После установки параметров команды InsertEvent соединение открывается, команда выполняется и происходит считывание результатов в экземпляре myEvent с помощью команды ExecuteReader объекта SQLCommand InsertEvent. Команда Read объекта SQLDataReader выполняет переход к следующей строке набора данных, представляющей первую строку во вновь открытом наборе данных.
Если считывание myEvent происходит без перехода к первой строке, в ADO.NET возникает ошибка. Локальный экземпляр anEvent обновляется новым ID, так как база данных генерирует ID для конкретного класса anEvent.
Многие программисты, знакомые с версиями ADO, предшествовавшими технологии ADO.NET, удивятся тому, как используется порядковая позиция поля ID, на которую ссылаются для получения значения ID экземпляра mEvent. Порядковое значение любого поля не должно использоваться для обращения к значению в наборе записей. SQLDataReader похож на набор записей ADO. Если таблица базы данных обновляется с добавлением нового столбца, то набор записей ADO может записать неправильное значение поля. Это зависит от того, в каком месте таблицы добавлен новый столбец. Однако в технологии ADO.NET этой проблемы не существует, так как порядковая позиция определяется в терминах экземпляра адаптера данных. Адаптер данных обеспечивает определенный уровень абстрагирования от уровня данных, поэтому программист может обращаться к порядковой позиции, не опасаясь, что изменения в таблице базы данных повредят программное обеспечение.
Компонент Data Adaptor
После установки подключения веб-служба узнает источник данных и аутентификационные данные, необходимые для предоставления этому источнику. Далее веб-служба отправляет запрос источнику данных на получение данных. ADO.NET предлагает для этого еще один компонент – адаптер данных (data adaptor). Версия адаптера данных для SQL Server 2000 использует провайдер SQL Server .NET с именем SQLDataAdaptor. OledbDataAdaptor (версия для OLE-DB) работает с предыдущими версиями SQL Server или базами данных, не имеющих конкретного провайдера. Адаптер данных можно установить, настроить и применить, как и любой другой класс в ADO.NET. ASP.NET содержит в инструментарии альтернативный компонент, который можно использовать в случае необходимости. Адаптер данных добавляется в дизайнере компонентов веб-службы и настраивается в окне свойств.
При добавлении компонента открывается окно мастера настройки адаптера данных (Data Adaptor Configuration Wizard). Это окно при желании можно закрыть, а свойства настроить вручную.
Ниже приведены инструкции по работе с мастером настройки адаптера данных.
В стартовом окне нажмите на кнопку Next (Далее), чтобы начать настройку адаптера данных, добавленного в веб-службу.В окне Choose Your Data Connection (Выбор подключения к данным) (см. рис. 3.8) в ниспадающем списке выберите подключение к данным, настроенное для проекта. При нажатии на кнопку New Connection (Создать подключение) откроется окно Data Link Properties (Свойства подключения к данным) (см. рис. 3.5) для настройки соединения. В нашем примере выберите ранее созданное подключение.
Рис. 3.8. Мастер настройки адаптера данных: выбор подключения к данным
После выбора подключения нажмите на кнопку Next (Далее), и мастер предложит выбрать метод запроса данных из источника в окне Choose A Query Type (Выбор тип запроса) (см. рис. 3.9).
Рис. 3.9. Мастер настройки адаптера данных: выбор типа запроса
Выберите Use SQL Statements (Использовать операторы SQL), и мастер сгенерирует набор командных объектов (с помощью класса SQLCommand или OledbCommand) в функции InitializeComponent класса веб-службы.
Командные объекты будут созданы с набором SQL-команд, которые используют псевдонимы каждого имени поля. С помощью ссылки на псевдоним в экземпляре командного объекта можно установить значения рассматриваемого поля.
Выберите Create New Stored Procedures (Создать новые сохраненные процедуры) или Use Existing Stored Procedures (Использовать имеющиеся сохраненные процедуры), и мастер запросит дополнительную информацию о таблицах данных, необходимую для построения и связи сохраненных процедур.
В нашем примере выберите опцию Use SQL Statements.Нажмите на кнопку Next (Далее) для перехода в окно Generate The SQL Statements (Генерация выражений SQL). Введите команду Select SQL для набора данных, используемых адаптером при построении выражений SQL (см. рис. 3.10). SQLDataAdaptor и OledbDataAdaptor поддерживают интерфейс для выполнения операторов Select (Выбор), Insert (Вставка), Delete (Удаление) и Update (Обновление). Мастер генерирует команды SQL для управления данными, устанавливаемыми в адаптере данных. Он запрашивает выражение SQL Select для создания текста команд Select, Insert, Delete и Update.
Рис. 3.10. Мастер настройки адаптера данных: генерация выражений SQL
После ввода в поле оператора Select теста select * from tblEvents
нажмите на кнопку Next (Далее), чтобы отобразить окно подтверждения View Wizard Results (Просмотр результатов работы мастера) (см. рис. 3.11). В этом окне описываются действия, выполненные с кодом веб-службы. При возникновении проблем с анализом выражения SQL, введенного в предыдущем шаге, в этом окне вы не увидите все возможные комментарии SQL, показанные на рис. 3.11. Нажмите на кнопку Back (Назад) и повторите введенную команду SQL или выберите создание сохраненных процедур на сервере базы данных.
Рис. 3.11. Мастер настройки адаптера данных: просмотр результатов работы
В нашем примере адаптер данных называется SQLDataAdaptor1, так как дизайнер компонентов присваивает это имя по умолчанию любому компоненту SQLDataAdaptor, добавляемому в представлении Design (Дизайн).
Это имя можно изменить в любой момент, и сгенерированный мастером код в подпрограмме InitializeComponent веб-службы автоматически обновится. В нашем примере имя SQLDataAdaptor изменено на EventsAdaptor в окне свойств.
Объектам SQLCommand, сгенерированным мастером настройки адаптера данных, присвоены имена SQLSelectCommand1, SQLDeleteCommand1, SQLInsertCommand1 и SQLUpdateCommand1. Имена командных объектов заменены на SelectEvent, DeleteEvent, InsertEvent и UpdateEvent соответственно. Это было сделано в окне свойств SQLDataAdaptor, т.е. изменено свойство имени, подчиненное динамическим свойствам Dynamic Properties каждого командного объекта. В листинге 3.5 приведен код, сгенерированный дизайнером компонентов для адаптера данных EventsAdaptor и объекта подключения к данным ServicesDBConn.
Листинг 3.5. Initialization Code Generated by the VS Designer for a Data Adaptor and a Data Connection (html, txt)
В листинге 3.5 приведена часть подпрограммы InitializeComponent, демонстрирующая компоненты SQLCommand, созданные дизайнером компонентов после переименования. После создания класса AppSettingsReader для получения параметров приложения из файла web.config созданы классы подключения, адаптера данных и команд. После инициализации класса подключения посредством строки подключения, полученной из файла web.config, класс адаптера данных присваивает каждый экземпляр объекта SQLCommand соответствующему свойству команды. Например, экземпляр команды DeleteEvent присваивается свойству DeleteCommand экземпляра SQLDataAdaptor с именем EventsAdaptor.
Дизайнер компонентов сгенерировал достаточно большой объем кода для настройки текста команд SQL и параметров каждого экземпляра командных объектов (это не отражено в листинге 3.5). Он определил каждое поле в наборе данных посредством псевдонима. Псевдонимы в командном объекте были установлены в качестве параметров. В листинге 3.6 приведен исходный код, реализующий текст команды SQL и параметры командного объекта InsertEvent.
Листинг 3.6.Initialization Code Generated by the VS Designer for a InsertEvent SQLCommand Object in Subroutine InitializeComponent(); (html, txt)
После инициализации класса подключения посредством строки подключения, полученной из файла web.config, класс адаптера данных присваивает каждый экземпляр объекта SQLCommand соответствующему свойству команды. Например, экземпляр команды DeleteEvent присваивается свойству DeleteCommand экземпляра SQLDataAdaptor с именем EventsAdaptor.
Дизайнер компонентов сгенерировал достаточно большой объем кода для настройки текста команд SQL и параметров каждого экземпляра командных объектов (это не отражено в листинге 3.5). Он определил каждое поле в наборе данных посредством псевдонима. Псевдонимы в командном объекте были установлены в качестве параметров. В листинге 3.6 приведен исходный код, реализующий текст команды SQL и параметры командного объекта InsertEvent.
// // InsertEvent // this.InsertEvent.CommandText = "INSERT INTO tblEvent" + "(Name, StartDate, Description) " + "VALUES (@Name, @StartDate, @Description); "+ "SELECT Name, StartDate, Description, ID " + "FROM tblEvent WHERE (ID = @@IDENTITY)";
this.InsertEvent.Connection = this.ServicesDBConn;
this.InsertEvent.Parameters.Add( new System.Data.SqlClient.SqlParameter ("@Name", System.Data.SqlDbType.VarChar, 50, "Name"));
this.InsertEvent.Parameters.Add( new System.Data.SqlClient.SqlParameter ("@StartDate", System.Data.SqlDbType.DateTime, 8, "StartDate"));
this.InsertEvent.Parameters.Add( new System.Data.SqlClient.SqlParameter ("@Description", System.Data.SqlDbType.VarChar, 200, "Description"));
Листинг 3.6. Initialization Code Generated by the VS Designer for a InsertEvent SQLCommand Object in Subroutine InitializeComponent();
Компонент Event Log
Весь код взаимодействия с базой данных в листинге 3.7 расположен в секции Try блока Try .. Catch. Если удовлетворяется условие исключения, то выполняется блок Catch. Экземпляр класса System.Exception передается в качестве аргумента функции Catch и содержит информацию об ошибке, возникшей в блоке Try. В листинге 3.7 экземпляр класса System.Exception упорядочен в строку с помощью функции ToString. Функция ToString представляет собой общую функцию, используемую со многими классами, так как она унаследована из класса object. Строковое представление сообщения об ошибке передается функции LogMessage, которая записывает ошибку в журнал Application Log в программе Event Viewer (Просмотр событий), после чего ошибка передается приложению-потребителю.
Функция LogMessage реализована таким образом, что в журнал Application несущего сервера можно записать любую информацию. Журнал Application поддерживает способ идентификации типа записываемого сообщения. Функция LogMessage записывает сообщения типа error или information в зависимости от переданного значения параметра Error. Если значение параметра Error равняется "истине", LogMessage идентифицирует сообщение в журнале Application как error (ошибка); в противном случае сообщение определяется как information (сведения). В листинге 3.9 приведен код функции LogMessage.
Листинг 3.9. LogMessage Function of the Events Class (html, txt)
Экземпляр объекта Log является журналом приложения несущего сервера. Дизайнер компонентов содержит компонент, представляющий журнал несущего сервера в программе Event Viewer (Просмотр событий). Просто вставьте элемент управления в представлении Design (Дизайн) веб-службы, после чего настройте свойства журнала на том узле, куда будут передаваться сообщения. В данном случае подходит журнал Application (Приложение), так как он фиксирует информацию о приложении.
Настройка компонента подключения к базе данных
Источником данных для веб-службы Events является база данных SQL Server 2000, поэтому добавим компонент SQLConnection. При поддержке другого типа базы данных используется компонент OleDBConnection. Компонент SQLConnection дает дополнительные возможности по управлению и повышает эффективности работы, в отличие от компонента OleDBConnection, поэтому последний используется только в случае необходимости. Если для источника данных отсутствует провайдер OLE-DB, то загрузите с сайта Microsoft доступен провайдер ODBC, поставляемый в отдельной библиотеке.
Свойство ConnectionString в окне свойств позволяет выбрать предыдущие подключения, настроенные на рабочей станции, или создать новое подключение. Для нашего примера создадим новое подключение (см. рис. 3.4).
увеличить изображение
Рис. 3.4. Выбор нового подключения в свойстве ConnectionString компонента SQLConnection
После выбора <New Connection...> в качестве параметра свойства ConnectionString откроется окно Data Link Properties (Свойства подключения к данным). В этом окне настраиваются все параметры, представленные в строке подключения ADO.NET. Окно свойств подключения к данным – это общее окно Visual Studio для настройки подключения ADO. Для веб-службы Events используется сервер базы данных, расположенный на сервере AMD1700, и база данных ASPNETServices (см. рис. 3.5).
Рис. 3.5. Настройка нового подключения к данным для веб-службы Events
Изменим имя компонента по умолчанию SQLConnection1 на более дружественное пользователю ServicesDBConn. После настройки и создания подключение SQLConnection работает в любом месте веб-службы. Класс Events наследуется из System.Web.Services. Класс WebService содержит множество классов и функций для взаимодействия с HTTP-соединением. В листинге 3.2 приведен исходный код, сгенерированный Visual Studio .NET для класса Events.
Листинг 3.2. Source Code of Class Events after SQLConnection Component Added and Configured (html, txt)
При работе с элементами управления веб-службы использование дизайнера компонентов не обязательно. Элементы управления добавляются в веб-службу посредством объявления и конструирования в файле Codebehind, как и другие переменные и классы. Например, экземпляр объекта SQLConnection можно создать и инициализировать в конструкторе класса Events. Код, приведенный в листинге 3.3, демонстрирует создание локального экземпляра объекта SQLConnection без использования дизайнера компонентов и компонента SQLConnection.
Листинг 3.3. Using SQLConnection Object without the Designer and Obtaining Connection String from the web.config File (html, txt)
В листинге 3.3 экземпляр myConn объявляется локально по отношению к классу Events. Строка подключения извлекается из файла web.config и используется в качестве конструктора экземпляра myConn. После создания экземпляра myConn в конструкторе Events его можно использовать в любом месте класса.
private System.Data.SqlClient.SqlConnection ServicesDBConn;
#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() { this.ServicesDBConn = new System.Data.SqlClient.SqlConnection(); // // ServicesDBConn // this.ServicesDBConn.ConnectionString = "data source=amd1700;initial catalog=ASPNETServices;" + "integrated security=SSPI;persist security info=False;" + "workstation id=AMD1700;packet size=4096";
}
/// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if(disposing && components != null) { components.Dispose(); } base.Dispose(disposing); }
#endregion }
Листинг 3.2. Source Code of Class Events after SQLConnection Component Added and Configured
При работе с элементами управления веб-службы использование дизайнера компонентов не обязательно. Элементы управления добавляются в веб-службу посредством объявления и конструирования в файле Codebehind, как и другие переменные и классы. Например, экземпляр объекта SQLConnection можно создать и инициализировать в конструкторе класса Events. Код, приведенный в листинге 3.3, демонстрирует создание локального экземпляра объекта SQLConnection без использования дизайнера компонентов и компонента SQLConnection.
public class Events : System.Web.Services.WebService { //locals to class private System.Data.SqlClient.SqlConnection myConn;
public Events() { //CODEGEN: This call is required by the //ASP.NET Web Services Designer InitializeComponent();
System.Configuration.AppSettingsReader myAppSettings = new System.Configuration.AppSettingsReader();
//get the connection string from web.config string sConnect = ((string) (myAppSettings.GetValue ("ProductionDB.ConnectionString", typeof(string))));
Работа с дизайнером компонентов
Инструментарий предоставляет множество компонентов для добавления в веб-службу. Некоторые из них доступны как в веб-формах, так и в веб-службах, однако в проекте веб-службы недоступны компоненты, предназначенные для создания графического интерфейса для пользователя. Добавление компонентов веб-службы в представлении Design (Дизайн) не влияет на файл Events.asmx. ASMX аналогичен файлу веб-формы ASPX, так как связывает язык, класс, файл Codebehind и файл источника с веб-службой. Отличие заключается в том, что ASMX не содержит другой информации, предназначенной для отображения.
Содержимое файла Events.asmx приведено в листинге 3.1. Если бы этот код предназначался для веб-формы, он содержал бы больший объем кода XML и HTML, определяющего параметры отображения; но он предназначен для веб-службы и содержит лишь одну строку текста.
<%@ WebService Language="c#" Codebehind="Events.asmx.cs" Class="myPortal.Events" %>
Листинг 3.1. Source Code of Web Service Events - File Events.asmx (html, txt)
При добавлении компонента подключения (или любого другого) в представление Design (Дизайн) в окне свойств настраиваются параметры этого компонента. Для каждого значения, устанавливаемого в этом окне, дизайнер компонентов генерирует код инициализации в файле Codebehind веб-службы и определяет предпроцессорную команду. Предпроцессорные команды в C# аналогичны командам в C++ и C, отличие же заключается в следующем.
Предпроцессорные команды языка C# не интерпретируются предпроцессором, отдельным от компилятора. Компилятор и предпроцессор представляют единое целое.Команды предпроцессора C# не могут указывать макросы.
Команда #region указывает область, расширяемую или сужаемую в редакторе Visual Studio .NET. Команда #region не оказывает функционального влияния на программное решение.
В коде, сгенерированном дизайнером компонентов, Visual Studio. NET объявляет три элемента:
ссылку на Icontainer с именем components;подпрограмму InitializeComponent;функцию Dispose.
Все компоненты, добавленные в представлении Design (Дизайн), инициализируются в подпрограмме InitializeComponent. Вызов подпрограммы InitializeComponent автоматически размещается в конструкторе веб-службы. Все свойства, устанавливаемые в окне свойств (см. рис. 3.3), присваиваются компоненту, которому они принадлежат. Комментарии, размещаемые дизайнером компонентов в данной области, предупреждают о том, что не следует изменять код вручную. Область кода, сгенерированного дизайнером компонентов, отображается в виде секции, взаимодействующей с представлением Design (Дизайн) веб-службы.
Экземпляр компонента IContainer используется функцией Dispose. Он содержит ссылки на все экземпляры компонентов внутри веб-службы. Метод Dispose предназначен для освобождения любых ресурсов, заявленных контейнером веб-служб.
Считывание параметров приложения из web.config
Файл web.config великолепно подходит для получения инициализационных данных, индивидуальных для веб-приложения. Это позволяет создавать решение программно, чтобы получить аргументы, связанных с конкретной реализацией, без внесения изменений в код других реализаций. С помощью класса AppSettingsReader осуществляется считывание данных из секции <appSettings> файла web.config. В листинге 3.4 приведен файл web.config, содержащий строку подключения к базе данных, полученную в листинге 3.3 в конструкторе Events.
Листинг 3.4. web.config File With <appSettings> Element That Contains Database Connection String (html, txt)
Дизайнер компонентов содержит механизм, использующий элемент appSettings файла web.config. В окне свойств компонента подключения в представлении Design (Дизайн) рассматриваемой веб-службы можно настроить параметр ConnectionString как набор динамических свойств DynamicProperties (см. рис.3.6).
Рис. 3.6. Свойства компонента подключения, использующие DynamicProperties для получения строки подключения ConnectionString
По умолчанию свойство ConnectionString не настроено на использование DynamicProperties. Каждое свойство нужно связать с ключом в файле web.config. Ключ представляет собой атрибут с именем key, расположенный в элементе add, подчиненном элементу appSettings (см. рис. 3.4). При нажатии на кнопку "..." в свойстве ConnectionString откроется диалоговое окно для выбора ключа (см. рис. 3.7).
Рис. 3.7. Связывание свойства ConnectionString с ключом в файле конфигурации
Создание тестовой структуры
Текущее значение, открытое в методе Open, сохраняется в свойстве Event класса Events. Класс Events предназначен для вызова методов Open или Add и возврата значения, определяющего успех или неудачу вызова. В случае удачного выполнения вызова из свойства Event можно получить данные Event.
Тестовая структура, предоставляемая технологией .NET, не отображает значения в свойстве веб-службы, и свойство нельзя определить как веб-метод с помощью идентификатора [WebMethod]. Идентификатор WebMethod располагается над всеми общими методами, представляемыми в качестве веб-служб XML. В данном случае нужна тестовая структура, использующая веб-службу и отображающая результаты таким образом, чтобы показать правильное функционирование кода.
Прекрасным механизмом для реализации тестовой структуры веб-службы являются веб-формы. Для метода Add класса Events была создана форма EventClient.aspx, реализующая добавление события. В веб-форму был добавлен элемент управления датой для фиксирования даты от конечного пользователя, и два текстовых поля для имени и описания события. Для отображения результирующего ID нового события после успешного выполнения функции Add в форму добавлено текстовое поле, отображающее ID, и кнопка Submit (Отправить), после нажатия на которую веб-форма выдает ответ. На рисунке 3.20 показан метод Add элемента управления датой после добавления события.
Рис. 3.20. Тестовая структура веб-формы с методом Add
Код веб-формы EventClient.aspx, приведенный в листинге 3.10, несложен. Как видно из рисунка 3.20, для каждого свойства класса anEvent в форме присутствует элемент управления. Кнопка Submit используется для инициализации вызова события Add. Код веб-формы EventClient.aspx содержит событие нажатия на кнопку элемента управления btnAdd. Веб-форма EventClient.aspx должна выполняться в том же веб-приложении, что и веб-служба. Ее назначением является только модульное тестирование кода, поэтому форма максимально упрощена; она реально обеспечивает разработчика обратной связью, информирующей о производительности веб-службы Events.
Листинг 3.10. Source Code for Events Add Function Test Harness - Web Form EventClient.aspx (html, txt)
Дизайнер компонентов автоматически добавил событие Click при двойном щелчке мышью на элементе управления btnAdd. В начале события Click созданы экземпляры класса anEvent и веб-службы Events. Так как эти классы находятся в едином пространстве имен, не нужно обращаться к пространству имен или размещать директиву using вверху исходного кода для пространства имен myPortal. Добавляемое событие представляется экземпляром anEvent с именем myEvent. Экземпляр класса Events называется myEvents. Свойства myEvent извлекаются из календарных элементов управления txtDescription и txtName. При заполнении пользователем экземпляра myEvent данными оно располагается в свойстве event экземпляра myEvents. Вызывается функция Add класса myEvents, и при ее успешной работе в элемент управления lblFeedback записывается сообщение об успехе функции; в противном случае – сообщение об ошибке.
Следует заметить, что в данном коде не предусмотрена обработка ошибок, поскольку он предназначен для тестирования и не используется при функционировании веб-службы. Отсутствие системы обработки ошибок позволит получить больше данных для проверки кода на устойчивость к ошибкам, возникающим в процессе работы.
Тестовую структуру следует содержать и хранить точно так же, как исходный код веб-службы. Она отражает работу программного решения и используется при проверке дальнейших усовершенствований веб-службы.
Создание веб-службы с помощью Visual Studio .NET
Для демонстрации процесса создания веб-службы в данной лекции представлено простое приложение для составления расписания по датам. Рассматриваемая система расписания состоит из трех следующих классов.
anEvent. Класс представляет событие, происходящее в данный момент времени и день.Events. Класс представляет коллективную группу экземпляров класса anEvent.EventClient. Веб-форма, использующая экземпляры Events и anEvent.
Класс Events является веб-службой, класс anEvent – классом, используемым веб-службой Events, а класс EventClient – веб-формой, использующей классы anEvent и Events. Все классы располагаются в едином пространстве имен myPortal. В результате компиляции проекта создается библиотека myPortal.dll. Файл Events.asmx указывает на класс в библиотеке myPortal.dll. Библиотека myPortal.dll также содержит класс веб-формы EventClient и класс anEvent. Файл EventClient.aspx направляет технологию .NET в myPortal.dll как в скомпилированный код, содержащий соответствующий класс.
Создадим новый проект веб-службы ASP.NET.
Откройте Visual Studio .NET. Отобразится начальная страница (если в Visual Studio .NET не отключено отображение начального окна). Как и в предыдущих версиях Visual Basic, предоставляется окно с шаблоном по умолчанию (вы можете его отключить).Выберите File\New Project (Файл\Создать проект) для открытия окна со списком типов проектов и соответствующих шаблонов.В списке слева выберите узел Visual C# Projects (Проекты Visual C#) – справа отобразятся шаблоны проектов для языка C#.Выберите шаблон ASP.NET Web Service (Веб-служба ASP.NET).Новой веб-службе в любом проекте по умолчанию присваивается имя Service1. В нашем примере проект называется myPortal (см. рис. 3.2). Задайте путь к корневому веб-каталогу сервера при помощи адреса URL или UNC. В URL указывается имя сервера по умолчанию localhost, если разрабатываемое программное решение располагается на рабочей станции при написании кода и модульном тестировании.Нажмите на кнопку OK.
Visual Studio .NET выполнит подключение к веб-серверу, указанному в диалоговом окне New Project (Новый проект), создаст новый виртуальный каталог и скопирует в него файлы веб-служб по умолчанию.
После генерации файлов проекта отобразится представление Design (Дизайн) веб-службы Service1, готовое к разработке. Visual Studio .NET присваивает веб-файлам веб-службы имена по умолчанию, поэтому их нужно переименовать.
Откройте Solution Explorer в меню View\Solution Explorer (Вид\Диспетчер программы).Щелкните правой кнопкой мыши на файле Service1.asmx и выберите Rename (Переименовать).Удалите имя Service1 и введите имя Events.Нажмите на клавишу Enter, и имена файлов ASMX, Codebehind и файла разрешения сменятся на Events.asmx, Events.asmx.cs и Events.asmx.res соответственно.
Класс, обеспечивающий работу веб-службы, будет по-прежнему называться Service1. Веб-служба исправно функционирует с различными именами, но мы все-таки сменим имя класса, присвоив ему имя службы.
Выделите файл Events.asmx в диспетчере Solution Explorer и нажмите на кнопку View Designer (Отобразить дизайнер). Файл Events.asmx.cs отобразится в дизайнере компонентов).Щелкните правой кнопкой мыши на файле Events.asmx.cs и выберите Properties (Свойства).В открывшемся окне свойство Name (Имя) содержит значение Service1. Удалите это значение.Введите в свойстве имени значение Events. Дизайнер компонентов автоматически изменит каждый экземпляр имени класса в файле Codebehind.
Веб-служба Events выполняет добавление, открытие или удаление экземпляров класса anEvent из портала. Данные экземпляра anEvent сохраняются в базе данных.
Рис. 3.2. Новый проект myPortal, создаваемый в диалоговом окне New Project (Новый проект)
Класс Events взаимодействует с базой данных, поэтому при построении веб-службы мы используем компоненты инструментария, реализующие получение и отправку (см. рис. 3.3). Компоненты добавятся в представление Design (Дизайн) веб-службы Events.
увеличить изображение
Рис. 3.3. Компоненты дизайнера форм, добавленные в представлении Design (Дизайн) веб-службы Events
Тестирование веб-службы
Помимо метода Add (см. листинг 3.7) и функции LogMessage (см. листинг 3.9) служба Events содержит три общих веб-метода: Delete, Open и HelloWorld. Методы Delete и Open аналогичны функции Add, т.е. выполняют чтение и запись отправляемых пользователем данных. HelloWorld является методом по умолчанию, размещаемым дизайнером компонентов во всех новых веб-службах для демонстрации создания метода, доступного из интернета.
Если файл ASMX веб-службы установлен в качестве стартового файла, веб-службу можно запускать и отлаживать в Visual Studio .NET. Нажмите на клавишу F5 для запуска компилятора; при отсутствии ошибок откроется браузер с отображением тестовой структуры технологии .NET (см. рис. 3.17).
Щелкните на любом из вызовов метода для открытия новой страницы, отображающей форму записи данных на базе параметров метода. Для описываемого метода под полями записи данных определены и описаны запрос и ответ HTTP и SOAP.
Рис. 3.17. Запрос веб-службы с помощью браузера
Данные, расположенные в текстовых полях на странице тестирования, будут переданы в качестве аргументов параметров метода после нажатия на кнопку Invoke (Запросить). На рисунке 3.18 показана страница тестирования метода Open в браузере.
Рис. 3.18. Метод Open веб-службы Events, запрошенный в браузере
Присвойте ID значение 13 и нажмите на кнопку Invoke (Запросить), в результате чего откроется другое окно браузера с результатом вызова метода Open в формате XML. Метод Open возвращает значение "истина" или "ложь" в случае успеха или неудачи (соответственно) выполняемой функции, поэтому такой ответ неинформативен. Он не позволяет выяснить, правильно ли веб-служба открыла запись; но обратная связь показывает, что веб-служба считает свои действия правильными, так как возвращается значение "истина" (см. рис. 3.19). Нам желательно увидеть данные, извлекаемые из источника данных, поэтому тестовая структура технологии .NET не подходит для модульного тестирования рассматриваемой службы.
Рис. 3.19. Ответ метода Open в браузере
DLL-библиотека обработки запросов
DLL-библиотека обработки запросов, создаваемая мастером проекта сервера ATL, реализуется таким образом, что разработчик изменяет код в файле заголовка, имя которого отражает имя проекта. Прототип класса с именем C<имя_проекта>Handler находится в файле заголовка. В проекте NewSimpleATLServer классу присвоено имя CNewSimpleATLServerHandler. В следующем листинге файла NewSimpleATLServer.h этот класс выполняет роль шлюза между классами, представляющими создаваемое программное обеспечение для интернета, и файлами SRF. Весь код можно разместить в классе обработки, однако это сделает его сложным для чтения и работы. Наилучшей стратегией в данном случае является использование данного класса для поддержки атрибутов тегов замещения файла SRF и для построения классов системы согласно структуре программы.
Листинг 4.5.
(html, txt)
Класс CNewSimpleATLServerHandler выполняет следующие задачи:
вывод сообщения "Hello World";подтверждение введенных пользователем данных;вывод отчета пользователю о его имени и любимом цвете
Весь код проекта NewSimpleATLServer расположен в файле заголовка для упрощения примера. Функция ValidateAndExchange является первой функцией, вызываемой при обработке запроса в DLL-библиотеке обработки, поэтому экземпляр класса m_HttpRequest проверяется на отправленные посредством HTTP данные с помощью функции m_HttpRequest.GetFormVars и размещения данных в экземпляре класса ChttpRequestParams с использованием ссылки Formdata. Функция Validate ссылки Formdata определяет отправление указанного значения ввода, его соответствие заданному диапазону, после чего значение записывается в переменную. Например, для подтверждения введенного значения используется следующая строка фрагмента кода, в которой Fname – это переменная типа Cstring, предназначенная для записи имени пользователя с длиной от 1 до 10 000 символов.
Validate("firstname", &FName, 1, 10000, &c)
Макрос ATLTRACE повсюду встречается в листинге обработчика CNewSimpleATLServer наряду с различными выражениями отладки в качестве аргументов.
ATLTRACE размещает аргумент в окне WebDbg при выполнении на узле (см. рис. 4.12). WebDbg представляет собой утилиту, поставляемую в комплекте со средствами Visual Studio .NET. В группе программ Visual Studio .NET обычно находится ссылка для запуска данной утилиты и именем ISAPI Web Debug Tool.
После запуска утилиту WebDbg нужно присоединить к имени канала AtlsDbgPipe с помощью команды File\Select Pipe\Pipe Name (Файл\Выбрать канал\Имя канала). Отлаживаемый процесс должен иметь разрешение на запись в указанный канал. Аутентификационные данные, под которыми работает IIS, устанавливаются с помощью команды File\Permissions (Файл\Разрешения). Если WebDbg выполняется на том же компьютере, что и веб-сайт, группе Everyone предоставляются разрешение на запись в канал. Если работа сайта осуществляется удаленно, то следует указать аутентификационные данные для определенного компьютера или домена.
Утилита WebDbg принимает через канал сообщения от программы, осуществляющей запись в этот канал. Сообщения по мере записи отображаются в окне WebDbg. Пошаговая обработка кода с помощью Visual Studio .NET IDE является хорошим способом первоначального тестирования кода, однако для использования в тех средах, где будет находиться программное обеспечение после перемещения из среды сервера разработки, целесообразно применение команды trace.
Рис. 4.12. Сообщения ATLTRACE, записанные в WebDbg
ATLTRACE работает только в конфигурации debug. Если программное решение скомпилировано в конфигурации release, макросы ATLTRACE игнорируются, и не нужно удалять какие-либо коды отладки. При запуске проекта NewSimpleATLServer пользователю отображается фраза hello world. Затем с помощью тега замещения HaveNameAndColor в файле SRF вызывается функция OnHaveNameAndColor. Она проверяет возвращаемое значение локальной переменной HaveNameandColor ("истина" или "ложь"), после чего возвращает соответствующий ответ, т.е. файл SRF либо отображает информацию, либо запрашивает у пользователя имя и любимый цвет.На рисунке 4.13 показан результат выполнения проекта NewSimpleATLServer после ввода пользователем информации. При получении результата, показанного на рисунке, файл SRF определяет значение, возвращенное переменной HaveNameandColor. Поскольку оно истинно, выполняется вызов функции OnYourFavoriteColor и OnYourName с помощью тегов замещения YourFavorityColor и YourName соответственно.
Рис. 4.13. Результат выполнения проекта NewSompleATLServer после ввода пользователем информации
Файлы ответа сервера
Далее нужно выполнить анализ информации, полученной от веб-пользователя, вынесение решения относительно полученных данных и возврат ответа пользователю. Посредством добавления определенного кода в проект NewSimpleATLServer файл SRF веб-приложения Hello World связывается с другим приложением, которое выполняет либо запрос имени и любимого цвета веб-пользователя, либо сообщает пользователю его имя и любимый цвет. После настройки файла SRF можно изменить класс DLL-библиотеки обработчика запросов в соответствии с требованиями SRF.
Обзор архитектуры ATL Server
ATL Server связывает классы и функции, хранящиеся в DLL, используя теги в текстовых файлах. В результате этого запросы к IIS могут вызывать функции внутри библиотек и возвращать запрашивающему клиенту содержимое текстового файла вместе с результатами вызова функции. ATL Server использует ISAPI для реализации механизма вызова между текстовыми файлами, IIS и библиотеками DLL с использованием системы командных тегов, поддерживаемой технологией .NET. Простейшее программное решение ATL Server включает в себя следующие компоненты.
Библиотека DLL расширения ISAPI.Библиотека DLL интернет-приложения или DLL поддержки запросов.Файл ответа сервера (SRF).Службы IIS.
При отправке запросов в IIS на ресурс, которым является источник ATL Server, IIS связывает вызов с библиотекой DLL расширения ISAPI. После получения этого запроса расширение ISAPI открывает и обрабатывает библиотеку DLL запрошенного веб-приложения или файл ответа сервера. Если запрошен файл ответа сервера, то вызывается тег замещения, обозначающий вызов функции из библиотеки DLL веб-приложения, и результаты работы вставляются в файл ответа сервера в месте расположения тега замещения. Комбинация результатов вызовов к DLL веб-приложения и содержимое файла ответа сервера возвращаются запрашивавшей стороне. Если DLL веб-приложения запрашивается напрямую, библиотека DLL расширения ISAPI выполняет соответствующий вызов (вызовы) и возвращает результаты в браузер.
На рисунке 4.1 приведен обзор архитектуры ATL Server.
Рис. 4.1. Обзор архитектуры ATL Server
Так как библиотека DLL расширения ISAPI может располагаться на несущем сервере не в корневом веб-каталоге, то IIS нужно знать, какие действия выполнять с файлом расширения ISAPI и файлами, связанными с библиотекой DLL расширения ISAPI (файлами ответа сервера и DLL веб-приложения). Чтобы сравнить программное решение для интернета, требующее текстовых файлов для обработки расширением ISAPI, мы будем использовать технологию ASP и противопоставим ее механизму IIS для связи файлов и расширения ISAPI.
IIS известно, как обрабатывать файлы ASP, поскольку имена файлов, оканчивающиеся на .asp обрабатываются с помощью расширения ISAPI с именем ASP.DLL.
Код внутри ASP.DLL открывает связанный ASP-файл и интерпретирует код в тегах ASP. Веб-формы и веб-службы, работающие с файлами .aspx и .asmx, используют такой же механизм, только они применяют технологию .NET вместо ASP.DLL для интерпретации кода и тегов, содержащихся в соответствующих файлах.
ATL Server с помощью библиотек DLL расширения ISAPI интерпретирует код, включенный в теги файла ответа сервера, и вызовы функций, определенные тегами замещения в библиотеке DLL веб-приложения. При создании веб-приложения с использованием файлов ASP разработчик ни в коем случае не станет перекомпилировать ASP.DLL таким образом, чтобы она содержала только код для обработки функций ASP. ASP.DLL не изменяется от одного ASP-приложения к другому; по существу, именно за счет этого работает одна библиотека DLL расширения ISAPI. Имейте в виду, что ATL Server создает особый интерпретатор для строящегося программного решения, оптимизированный именно для этого решения. Он также является библиотекой DLL расширения ISAPI, которая входит в проект ATL Server. Разработчик имеет прекрасную возможность модифицировать ее в соответствии с требованиями конкретного приложения, а не использовать конфигурацию по умолчанию.
Для использования службами IIS библиотеки расширения ISAPI файлы ответа сервера и файлы библиотеки DLL приложения необходимо связать с соответствующей библиотекой расширения ISAPI, аналогично тому, как файлы с расширениями .asp связаны с библиотекой ASP.DLL или файлы с расширениями .aspx связаны с интерпретатором технологии .NET aspnet_isapi.dll. Расширение имен файлов ответов сервера .srf и расширение .dll DLL-библиотек веб-приложения должны быть связаны с соответствующей DLL-библиотекой расширения ISAPI.
Ниже показано, как можно связать расширения имен файлов с расширениями ISAPI.
Откройте консоль MMC для IIS.Щелкните на значке папки Web Site (Веб-узел) в дереве папок, чтобы развернуть список экземпляров веб-сервера на сервере, затем щелкните на экземпляре веб-сайта, который необходимо настроить, для отображения его содержимого.Откройте окно свойств для любого веб-объекта или виртуального каталога и нажмите на кнопку Configuration (Настройка) во вкладке Home Directory (Домашний каталог) или Virtuel Directory (Виртуальный каталог) соответственно.
Откроется апплет Application Configuration (Настройка приложения) (см. рис. 4.2).Свяжите файл и путь к нужной DLL- библиотеке расширения ISAPI на сайте. После этого IIS необходимо перезапустить.
Рис. 4.2. Окно настройки приложения предназначено для связывания файлов с расширениями
Расположение DLL-библиотеки веб-приложения, используемой файлом ответа сервера, определяется в самом файле ответа сервера. Она должна находиться в корне виртуального каталога. Файл ответа сервера содержит тег обработчика, определяющий относительное расположение этой библиотеки. (Для получения более подробной информации о тегах обработчика обратитесь к разделу "Файлы ответа сервера".) Когда в IIS направляется HTTP-запрос на файлы ответа сервера или библиотеку DLL веб-приложения, IIS с помощью связей файлов определяет, где искать эту библиотеку для обработки и интерпретации запроса.
Ни одна из задействованных библиотек не является DLL-библиотекой модели компонентных объектов (COM), поэтому IIS и компоненты ATL Server для поиска нужных DLL-библиотек физически отыскивают их на узле по текущим файловым расположениям.
Многие из разработчиков знают, что расположение COM-объекта на узле определяется связыванием уникального идентификационного номера (CLSID) с путем к файлу DLL. Эта информация записывается в реестр Windows, и любое программное обеспечение, запрашивающее использование DLL-библиотеки COM- объекта, сможет работать с ней. Доступ к DLL с помощью ее физического нахождения и загрузки выглядит несколько устаревшим по сравнении с архитектурой, появившейся после технологии COM, но такое решение дает некоторые преимущества с точки зрения управления. Связи с файлами в IIS базируются на файловых расширениях. DLL-библиотека веб-приложения указывается посредством относительного пути. Перемещение файлов на другой сервер нарушает связи файлов IIS с DLL-библиотекой расширения ISAPI, но другие файлы перемещаются так, как если бы они являлись статическим содержимым, поскольку их расположение относительно друг друга контролируется.
Опции поддержки разработчика в мастере проекта сервера ATL
Вкладка Developer Support Options (Опции поддержки разработчика) мастера проекта сервера ATL содержит три опции (см. рис.4.10).
Рис. 4.10. Параметры поддержки разработчика в мастере проекта сервера ATL
Generate TODO Comments (Генерировать комментарии TODO). Добавляет в код комментарии, сообщающие разработчику о том, что необходимо сделать в рассматриваемой секции.
Примечание. Комментарии TODO – это инструкции о назначении рассматриваемого фрагмента кода, размещаемые в программе.
Attributed Code (Код с атрибутами). Обеспечивает поддержку тегов атрибутов для указания вызовов функции.Custom Assert And Trace Handling Support (Поддержка особых опций отладки). Обеспечивает наличие глобально доступного экземпляра класса CDebugReportHook для фиксирования информации из макроса отладки ATL.
Опция Attributed Code (Код с атрибутами) размещает в DLL-библиотеке обработчика запросов уже знакомые нам обработчики тегов для связывания тегов, используемых в SRF-файлах, с ее функциями. В качестве примера рассмотрим демонстрационный метод hello world с кодом с атрибутами:
[ tag_name("Hello") ] HTTP_CODE OnHello(void) { m_HttpResponse << "Hello World!"; return HTTP_SUCCESS; }
Код без атрибутов поддерживает имена обработчиков тегов в SRF, связываемые с рассматриваемой функцией. Он используется макрос REPLACEMENT_METHOD_ENTRY для привязки имени тега к имени функции. Отказ от использования атрибутов предпочтителен при решении задачи о присвоении обработчиков тегов функциям в проектах с большим объемом кода. DLL-библиотека обработчика запросов не содержит путаницы тегов, присущей синтаксису тегов в виде скобок; все функции с тегами определяются в одном месте. В следующем листинге приведен фрагмент кода, использующий для функции OnHello обработчики тегов без атрибутов:
// TODO: Add additional tags to the replacement method map BEGIN_REPLACEMENT_METHOD_MAP(CNonAttributedCodeHandler) REPLACEMENT_METHOD_ENTRY("Hello", OnHello) END_REPLACEMENT_METHOD_MAP()
HTTP_CODE ValidateAndExchange() { // TODO: Put all initialization and validation code here
// Set the content-type m_HttpResponse.SetContentType("text/html");
return HTTP_SUCCESS; }
protected: // Here is an example of how to use //a replacement tag with the stencil processor HTTP_CODE OnHello(void) { m_HttpResponse << "Hello World!"; return HTTP_SUCCESS; }
Опция Custom Assert And Trace Hendling Support (Поддержка особых опций отладки) объявляет глобально доступный экземпляр класса CDebugReportHook в DLL-библиотеке расширения ISAPI. С помощью ATLTRACE и других макросов разработчик записывает код в DLL-библиотеку обработчика запросов, исполняемый только в процессе отладки, а также осуществляет вывод данных в программу, предназначенную для считывания каналов с именами типа WebDbg.exe. В следующем листинге объявление CDebugReportHook действительно только в том случае, если определен макрос _DEBUG:
// For custom assert and trace handling with WebDbg.exe #ifdef _DEBUG CDebugReportHook g_ReportHook; #endif
Параметры приложения в мастере проекта сервера ATL
Параметры приложения обычно базируются на особенностях выбранного шаблона проекта (см. рис. 4.9). При создании веб-службы с помощью ATL Server следует отметить опцию Create As Web Service (Создать как веб-службу). Она исключает использование прочих опций вкладки Application Options (Опции приложения). При создании проекта ATL Serverа доступ к этим опциям открыт. Если опция Stencil Processing Support (Поддержка обработки шаблона) не включена, то недоступны два элемента, подчиненные опциям в секции начального файла ответа сервера.
Рис. 4.9. Вкладка Application Options (Параметры приложения) в мастере проекта сервера ATL
Опция Validation Support (Поддержка подтверждения) обеспечивает функцию ValidateAndExchange в файле заголовка класса обработчика. В других мастерах инициализационный код вставляется в функцию ValidateAndExchange. Эта функция является членом базового класса CRequestHandlerT, предназначенного для замены особым кодом инициализации и подтверждения, связанным с библиотекой DLL веб-приложения. DLL веб-приложения наследуется из класса CRequestHandlerT, и поэтому библиотека DLL веб-приложения также называется DLL-библиотекой обработчика запросов (см. рис. 4.1). CRequestHandlerT осуществляет HTTP-взаимодействия между DLL-библиотекой обработчика запросов и ISAPI, обеспечивая определенный уровень абстракции для ISAPI. Среди прочих возможностей этой библиотеки, наследуемой из класса CRequestHandlerT, можно выделить экземпляры классов m_HttpResponse и m_HttpRequest. Эти классы дают разработчику механизмы чтения и записи запроса или ответа HTTP.
Опция Stencil Processing Support (Поддержка обработки шаблона) добавляет в код демонстрационную функцию hello world и демонстрационный обработчик этой функции. Доступ к области Options For The Initial Server Response File (Опции начального файла ответа сервера) открывается при включении опции Stencil Processing Support (Поддержка обработки шаблона) и позволяет изменять настройки начального файла SRF, сгенерированном мастером.
Если во вкладке Application Options (Параметры приложения) не отмечено ни одной опции, то будет сгенерирована программная структура, аналогичная простому проекту расширения ISAPI. Для многих программистов, работающих с ISAPI и не нуждающихся в функциональности SRF, этот вариант более предпочтителен. ATL Server не нужен файл SRF для функционирования, так как в любой момент можно осуществить прямые вызовы DLL-библиотеки обработчика запросов. Действительно, при выборе опции Generate Combined DLL (Генерировать комбинированную DLL) во вкладке Project Settings (Параметры проекта), если не включены опции вкладки Application Settings (Параметры приложения), будет создана структура, аналогичная проекту расширения ISAPI, в котором отсутствуют многие функции поддержки ATL.
Ниже приведен код класса для DLL-библиотеки обработчика запросов, при создании которого во вкладке Application Options (Параметры приложения) не были включены опции:
Листинг 4.3.
(html, txt)
Параметры проекта
Во вкладке Project Settings (Параметры проекта) мастера проекта сервера ATL (см. рис. 4.7) указывается виртуальный каталог, в который будет записан проект после компиляции. Этот каталог можно сменить в любое время с помощью окна свойств проекта. Вы можете также переименовать проект и каталоги после генерирования мастером проекта сервера ATL файлов программного решения, но возможность генерации одной DLL для хранения кода ISAPI и кода веб-приложения нужно указать до окончания работы мастера.
Рис. 4.7. Параметры проекта в мастере проекта сервера ATL
Опытный разработчик сможет самостоятельно настроить параметры проекта для смены его типа, но с точки зрения надежности и быстроты операции разумнее изменить параметры мастера для некоторых конфигураций создаваемых двоичных файлов.
Параметры сервера в мастере проекта сервера ATL
Во вкладке Server Options (Параметры сервера) мастера проекта сервера ATL (см. рис. 4.8) устанавливается поддержка дополнительной интеграции со службами узла сервера и управление сеансами. Следует отметить, что сеанс может записываться в источник данных, имеющий провайдера OLE-DB. Это относится к разработке веб-кластера, когда требуется размещение данных сеанса внутри источника данных, если другие серверы, участвующие в поддержке веб-решения, должны иметь доступ к сеансу.
Рис. 4.8. Вкладка Server Options (Параметры сервера) мастера проекта сервера ATL
Если проект сервера ATL создан для функционирования на одном сервере, или если не требуется взаимодействие с другими веб-серверами, использующими сеанс, выберите опцию Memory-Backed Session State Services (Службы состояния сеанса, хранимые в памяти) для обеспечения более высокой производительности. Опция OLE DB-Backed Session State Services (Службы состояния сеанса, хранимые в OLE DB) позволяет расширять программное решение, т.е. установить его в распределенной аппаратной среде без изменения кода. Если программное решение требует поддержки сеансов, отметьте опцию Session Services (Службы сеансов). В зависимости от требуемого уровня поддержки выберите соответствующую опцию хранения: в OLE DB или в памяти.
При генерации мастером кода создается класс с таким же именем, как у проекта, к началу имени присоединяется символ "C", а к концу добавляется слово "Handler". Этот класс будет интерфейсом веб-приложения в IIS за счет включения в себя обработчиков тегов. Пусть проект называется atlServer4 ((см. рис. 4.7), тогда мастер для поддержки обработчиков тегов создаст класс CatlServer4Handler.
Включение любой из следующих опций во вкладке Server Options (Параметры сервера) мастера позволит добавить в класс обработчик кода, объявляющий и инициализирующий указатели на соответствующий класс поддержки.
Blob Cache. Добавляет указатель на экземпляр класса ImemoryCache для управления случайными участками памяти.File Cache. Добавляет указатель на экземпляр класса IfileCache для управления именами файлов.Data Source Cache. Добавляет классы в проект ATL Server и проект ISAPI для управления кэшированием подключений OLE DB каждого потока.Predefined Performance Counters. Добавляет классы для интеграции проекта со счетчиками производительности perfmon.Browser Capabilities Support. Добавляет указатель на экземпляр класса IbrowserCapsSvs для управления возможностями браузера.
Если в мастере выбраны опции File Cache (Кэш файлов), Blob Cache (Кэш памяти) и Browser Capabilities Support (Поддержка возможностей браузера), а проект называется SimpleATLServer, то будет сгенерирован класс CSimpleATLServerHandler и записан в заголовок SimpleATLServer.h. В частной секции класса CSimpleATLServerHandler будут сгенерированы следующие объявления с комментариями перед кодом:
// File cache support // CComPtr<IFileCache> m_spFileCache;
// Blob cache support // CComPtr<IMemoryCache> m_spBlobCache;
// Data Source cache support // CComPtr<IBrowserCapsSvc> m_spBrowserCaps;
Примечание. В приведенном коде указатель Browser Capabilities Support (Поддержка возможностей браузера) неправильно определен в комментарии как поддержка кэша источника данных, что привело к незначительной ошибке в шаблоне мастера проекта сервера ATL.
При использовании указателей на File Cache (Кэш файлов), Blob Cache (Кэш памяти) и Browser Capabilities Support (Поддержка возможностей браузера) с каждого из них нужно снять статус комментария. Указатели инициализируются в общей функции ValidateAndExchange. Она включается в каждый класс обработчика, генерируемый мастером проекта сервера ATL, если отмечена опция Validation Support (Поддержка подтверждения) во вкладке Application Options (Параметры приложения) (см. следующий раздел). С фрагментов кода, отвечающих за инициализацию соответствующего указателя, также нужно снять статус комментария.
Листинг 4.1.
(html, txt)
В ассоциированное расширение ISAPI следует добавить код для поддержки элементов, выбранных во вкладке Server Options (Параметры сервера) мастера. В отличие от кода класса обработчиков код поддержки в расширении ISAPI не является закомментированным, он входит в программное решение независимо от того, используется он или нет. Не включайте поддержку функциональности – это позволит сократить количество ресурсов.
Поддержка файлового кэширования добавляет указатель класса для поддержки функций управления указателями файлов, относящихся к чтению и записи файлов.
Если указатель на указатель класса IbrowserCaps передается функции GetCaps класса IbrowserCapsSvc вместе с указателем на контекст сервера, то экземпляр IbrowserCaps позволяет выполнить запрос возможностей браузера. Эта информация определяется экземпляром класса IbrowserCaps с помощью сравнения значения HTTP_USER_AGENT, отправленного веб-серверу с запросом HTTP, с соответствующим значением в файле browsercap.ini (он обычно находится в папке $(windows)\system32\inetsrv\). В файле browsercap.ini приведен HTTP User Agent и определены его параметры. Например, для браузера Internet Explorer (IE) 5 в файле browsercap.ini указано следующее:
Листинг 4.2.
(html, txt)
Опция Resource Language (Язык источника) во вкладке Server Options (Параметры сервера) обеспечивает поддержку использования других языков для генерирования текста копии в файлах источников проекта. Необходимо установить Visual Studio .NET с поддержкой языков для нужного ресурса, чтобы открыть доступ к этой опции.
// Get the IBrowserCapsSvc service from the ISAPI extension // if (FAILED (m_spServiceProvider->QueryService // (__uuidof(IBrowserCapsSvc), // &m_spBrowserCaps))) // return HTTP_FAIL;
return HTTP_SUCCESS; }
Листинг 4.1.
В ассоциированное расширение ISAPI следует добавить код для поддержки элементов, выбранных во вкладке Server Options (Параметры сервера) мастера. В отличие от кода класса обработчиков код поддержки в расширении ISAPI не является закомментированным, он входит в программное решение независимо от того, используется он или нет. Не включайте поддержку функциональности – это позволит сократить количество ресурсов.
Поддержка файлового кэширования добавляет указатель класса для поддержки функций управления указателями файлов, относящихся к чтению и записи файлов. Непосредственно содержимое файла не хранится в классе кэша; он содержит информацию о расположении файлов, их именах и размерах. При удалении элементов из кэша они удаляются с жесткого диска, поэтому кэширование файлов предназначено только для управления временными файлами.
Кэш памяти необходим для взаимодействия с фрагментами памяти переменного размера в отличии от других классов кэширования памяти ATL Server, поддерживающих фрагменты памяти определенного размера.
Кэш источника данных обеспечивает функциональность, присущую и другим классам кэширования, исключая хранение подключений к источникам данных.
При выборе опции Predefined Performance Counters (Предопределенные счетчики производительности) в расширении ISAPI размещается код, реализующий обновление счетчиков ISAPI для perfmon согласно взаимодействию веб-приложения с IIS. Разработчик не участвует в написании кода, весь код, необходимый для обеспечения функциональности, генерируется мастером в файле реализации расширения ISAPI.
Предопределенными счетчиками производительности являются следующие.
Active Threads (Активные потоки). Активные потоки, используемые процессом веб-приложения.Average Response Time (Среднее время ответа). Усредненное время возврата HTTP-ответа веб-приложением.Current Queued Requests (Текущие запросы в очереди).
Работа с мастером проекта сервера ATL
Мастер проекта сервера ATL позволяет настраивать параметры, используемые при создании проекта. Он предлагает множество возможных вариантов проекта ATL Server. Некоторые элементы можно изменить на страницах окна свойств проекта уже после создания проекта, а некоторые нужно установить в мастере, так как позже это сделать уже будет нельзя. Visual Studio .NET позволяет корректировать любой проект, менять его тип; а вот аналогичное изменение, производимое вручную, займет много времени. При смене типа проекта вы предотвратите появление проблем, просто сохранив нужный код и вставив его в проект, сгенерированный корректным шаблоном проекта в Visual Studio .NET. Знание опций, доступных в мастере проекта сервера ATL, позволит сэкономить время и более детально ознакомиться с этим компонентом.
Создание простого проекта ATL Server
Создадим проект ATL Server.
Откройте Visual Studio .NET.Выберите команду File\New\Project (Файл\Создать\Проект) для открытия диалогового окна New Project (Новый проект) (см. рис. 4.3).
Рис. 4.3. Диалоговое окно New Project (Новый проект) с шаблоном проекта ATL Server
Visual Studio .NET предлагает множество шаблонов ATL для веб-решений и решений ATL. В рамках нашего упражнения выберем шаблон ATL Server Project (Проект сервера ATL). Будьте внимательны: не следует выбирать шаблон ATL Project (Проект ATL), так как он не содержит веб-компонентов. Шаблон ATL Project (Проект ATL) обеспечивает среду для разработки классической ATL DLL или исполняемого файла, использующего библиотеки ATL.
Шаблон ATL Server Web Service (Веб-служба сервера ATL) создает проект веб-службы, аналогичный шаблонам проектов веб-служб языков Visual Basic и C#, за исключением того, что данный проект использует язык C++. Для веб-службы создается связанное расширение ISAPI, установка и управление которым осуществляется отдельно от DLL-библиотеки веб-службы. По аналогии с файлом .asmx веб-служб в C#, являющимся механизмом управления DLL-библиотекой, веб-служба сервера ATL для этой цели использует файлы HTML.
Введите имя проекта, после чего нажмите на кнопку Next (Далее) для запуска мастера проекта сервера ATL (ATL Server Project Wizard); откроется окно с обзором создаваемого проекта.Окно мастера проекта сервера ATL имеет четыре раздельные области, предназначенные для изменения параметров проекта ATL Server перед генерацией файлов (см. рис. 4.4). Если параметры по умолчанию известны и подходят для использования, то нажмите на кнопку Finish (Готово) для создания файлов проекта.
Рис. 4.4. Окно Overview (Обзор) мастера проекта сервера ATL
После нажатия на кнопку Finish (Готово) Visual Studio .NET начнет генерирование файлов согласно параметрам по умолчанию мастера проекта сервера ATL. Любой из упомянутых в шаге 3 шаблонов (ATL Server Web Service [Веб-служба сервера ATL] или ATL Server Project [Проект сервера ATL]) сгенерирует в Visual Studio .NET два проекта.
Стартовый проект представляет собой главный проект, имя которого мы ввели в диалоговом окне New Project (Новый проект). Второй генерируемый проект носит то же имя, что и стартовый, но к его имени добавляется окончание ISAPI. Создаваемому проекту ATL Server присвоено имя NewSimpleATLServer (см. рис. 4.3). В Visual Studio .NET имеется Solution Explorer (Обозреватель решения) для просмотра проектов и связанных с ними файлов. В его окне представлено иерархическое дерево проектов и файлов, связанных с открытым в данный момент программным решением. Solution Explorer можно открыть с помощью команды View\Solution Explorer (Вид\Обозреватель решения). В окне Solution Explorer мы видим проекты NewSimpleATLServer и NewSimpleATLServerISAPI. Проект NewSimpleATLServer содержит код, специфичный для приложения. Его результатом является DLL-библиотека веб-приложения и файл ответа сервера (SRF). Продуктом проекта NewSimpleATLServerISAPI является только ISAPI DLL.
В отличие от шаблонов веб-служб для C# и Visual Basic, в локальный экземпляр IIS не добавляется автоматически виртуальный каталог. Visual Studio .NET можно настроить на реализацию файлов, устанавливающих программное решение ATL Server на IIS. При этом будет производиться установка лишь в первый веб-экземпляр, загруженный в IIS. При установке в другой веб-экземпляр (не в первый, являющийся веб-сайтом по умолчанию) следует провести данную операцию вручную. Для настройки Visual Studio на автоматическую установку решения ATL Server в IIS выполните следующие шаги.
В меню Visual Studio .NET выберите Project\Properties (Проект\Свойства) для открытия окна свойств (см. рис. 4.5). Проект сервера ATL состоит из двух проектов (если только он не настроен на использование одной библиотеки DLL). Окно свойств отображает параметры выбранного в данный момент проекта Visual Studio. Изменить проект можно, выделив его в окне Solution Explorer.
увеличить изображение
Рис. 4.5. Окно свойств проекта и окно Solution Explorer (Обозреватель решения)
В окне свойств выделите внизу левой панели окна узел Web Deployment (Веб-реализация). Каждый из узлов в панели слева обозначается значком папки. Выбор любого из них обновит содержимое правой панели и отобразит элементы управления, используемые для настройки конфигурации выделенного узла.В окне Solution Explorer выберите проект DLL-библиотеки расширения ISAPI. Если имя проекта не было изменено, то к имени обычно присоединяется окончание ISAPI.Для свойства Relative Path (Относительный путь), отображаемого в области справа, введите значение bin. В результате DLL-библиотека расширения ISAPI будет расположена в подкаталоге bin папки, на которую указывает виртуальный каталог IIS. Вы можете указать другое имя каталога.Установите параметр Virtual Directory Name (Имя виртуального каталога) равным имени виртуального каталога, в который устанавливаются файлы проекта ATL Server. Если виртуальный каталог не существует, он будет создан. Ниспадающий список позволяет легко выбрать имя проекта.Параметр Application Mappings (Связи приложения) нужно установить равным .srf;.dll. В созданном виртуальном каталоге будут присутствовать эти связи.Выберите проект DLL-библиотеки веб-приложения в Solution Explorer (Обозреватель решения) для обновления окна и отображения параметров проекта.По аналогии с проектом ISAPI выберите узел Web Deployment (Веб-реализация) в левой области окна внизу (если вы еще не сделали это).Установите такие же значения параметров, как в шагах 4 и 5. Имя виртуального каталога должно совпадать с именем проекта ISAPI. Параметр относительного пути может отличаться от относительного пути проекта ISAPI. Связи приложения устанавливать не нужно.Нажмите на кнопку OK, чтобы сохранить изменения в конфигурации и закрыть окно.
После установки относительного пути, имени виртуального каталога и связей приложения для проектов в решении ATL Server реализация файлов произойдет при первом же выполнении команды построения.
Нажмите на клавишу F5, и, независимо от того, какое окно выбрано в Visual Studio .NET, начнется построение, реализация и запуск проекта NewSimpleATLServer.
Появится окно, информирующее об истечении срока действия файлов с запросом на разрешение повторной компиляции. После успешной компиляции двоичных файлов обработчика запросов DLL и расширения ISAPI эти файлы будут перемещены вместе с демонстрационным файлом SRF в место расположения в корневом веб-каталоге веб-сайта IIS по умолчанию. Visual Studio .NET попробует присоединить себя к IIS и провести пошаговую отладку кода, в результате чего, скорее всего, появится следующее сообщение об ошибке.
Запомните. Имя проекта StartUp в любом решении Visual Studio .NET указывается в Solution Explorer жирным шрифтом. Если решение содержит несколько проектов, то шаблон проекта, как правило, автоматически устанавливает нужный проект как StartUp. Тем не менее, убедитесь в том, что в качестве стартового (StartUp) установлен нужный проект, так как проект StartUp устанавливается случайным образом. Для присвоения проекту статуса StartUp щелкните правой кнопкой мыши на проекте в окне Solution Explorer и в контекстном меню выберите Set As StartUp Project (Сделать стартовым проектом).
Visual Studio .NET не устанавливается с поддержкой отладки ATL Server. По умолчанию устанавливается компонент Full Remote Debugging (Полная удаленная отладка), обеспечивающий отладку веб-форм и веб-служб Visual Basic и C#. Решениям C++ необходима Native Remote Debugging (Обычная удаленная отладка). С помощью программы установки Visual Studio .NET добавляется необходимая поддержка (см. рис. 4.6). Откройте программу установки и запустите процесс инсталляции. В окне, показанном на рис. 4.6, выберите Native Remote Debugging (Обычная удаленная отладка).
увеличить изображение
Рис. 4.6. Установка Native Remote Debugging (Обычная удаленная отладка)
После установки обычной удаленной отладки и правильной настройке ее параметров откроется окно браузера с отображением сообщения: "This is a test: Hello World!". На данном этапе может возникнуть ошибка по причине того, что файловые расширения .dll и .srf не связаны с ассоциированной DLL-библиотекой расширения ISAPI в рассматриваемом экземпляре IIS или виртуальном каталоге.В этом случае откройте связи приложения (см. рис. 4.2) и проверьте правильность связи файлов .dll и .srf с нужной библиотекой.
Поскольку сложная конфигурация ATL Server требует запуска программы Hello World, разработчик должен хорошо разбираться в процессах, происходящих внутри IIS и технологии .NET. Использование мощи ATL Server очень выгодно для разработки, но требует серьезных навыков и знаний от программиста.
Совет. Если при работе с IIS и ATL Server по непонятной причине возникают неполадки, попробуйте перезапустить веб-службы. Это помогает, если разработчик или системный инженер установил связь с расширением ISAPI вручную, либо после внесения изменений в конфигурацию экземпляра IIS или виртуального каталога.
Теги Handler и Subhandler
Первым тегом любого файла SRF является тег handler. Тег handler указывает библиотеку DLL, к которой осуществляется доступ при поиске функций, указанных тегами замещения в файле SRF. Также можно указать тег subhandler. В одном файле SRF можно вызвать функции из одной или нескольких DLL-библиотек обработки запросов. В теге handler или subhandler используются псевдонимы, с помощью которых формируются теги замещения для вызова функций из рассматриваемой библиотеки DLL обработчика запросов с применением имени alias.function. Тег handler имеет следующий синтаксис:
{{handler <handler name>.dll/Default}}
По умолчанию Visual Studio .NET записывает файлы DLL в каталог с файлами SRF. Размещение двоичных файлов, как правило, представляет определенный уровень абстракции, отличающийся от кода файлов SRF, поэтому двоичные файлы предпочтительнее записывать в отдельный каталог на сервере. Для этого обычно используется подкаталог корневого веб-каталога или каталог корневого виртуального каталога с именем bin. При использовании подкаталога bin для хранения библиотек DLL тег handler выглядит следующим образом:
{{handler bin\<handler name>.dll/Default}}
Теги в файлах ответа сервера
Файл SRF является хорошей альтернативой языкам Extensible Styleshet Language (XSL) или Extensible Stylesheet Language Transformation (XSLT) и веб-формам ASP.NET за счет предоставления механизма форматирования и отображения выходных данных ATL Server при отделении логики представления от бизнес-логики. Представление Design (Дизайн) в ATL Server предоставляет определенный уровень абстракции для доступа к DLL-библиотеке обработчика запросов и записи кода HTML (см. рис. 4.11). Используя теги в файле SRF, можно реализовать упрощенные сценарии, оптимизированные для управления вызовами функций в DLL-библиотеке обработчика запросов, аналогично файлам XSL и XSLT, которые анализируют и управляют содержимым XML. Файл XSL или XSLT содержат в верхней части инструкции для обозначения того, как нужно использовать файл, и в файле SRF имеется такой же элемент. Файл SRF поддерживает упрощенные возможности циклов и вынесения решений, как и файлы XSL и XSLT.
увеличить изображение
Рис. 4.11. Представление Design (Дизайн) файла NewSimpleATLServer.srf
Теги в SRF обозначаются двумя парами фигурных скобок, содержащих внутри аргумент, обычно соответствующий атрибуту тега внутри DLL-библиотеки обработчика запросов. Атрибуты тега в DLL-библиотеке обработчика запросов связаны с функциями, выполняющими определенную задачу и возвращающими данные, предназначенные для вставки в файл SRF. Один файл SRF способен вызвать много DLL-библиотек обработки запросов. Файл SRF может включать в себя другие файлы SRF с помощью тега include и поддерживает комментарии в коде.
Теги замещения
Тег замещения наиболее часто используется в файле SRF. Теги замещения являются точкой доступа разработчика к функциям DLL-библиотек обработки запросов. Тег замещения осуществляет запрос ответа от библиотеки, содержащей нужную функцию, и вставляет ответ в том месте файла SRF, в котором находится тег замещения. Теги замещения поддерживают инструкции для вызова функций, выполняют передачу аргументов функции в DLL-библиотеку обработки запросов. Например, блок if..else..endif можно реализовать с помощью команды {{if<FunctionName>}}, являющейся начальной точкой блока if. Блоки Else и endif обозначаются командами {{else}} и {{endif}} соответственно.
В проекте NewSimpleATLServer SRF вызывает функцию по имени атрибута HaveNameAndColor, как показано в следующем коде. Если HaveNameAndColor возвращает значение "истина", отображаются имя и любимый цвет, введенные пользователем. Если один из элементов неизвестен, то функция HaveNameAndColor возвращает значение "ложь", и SRF запрашивает у пользователя имя, фамилию и любимый цвет. Теги замещения поддерживают инструкции while..endwhile для реализации циклов.
Листинг 4.4.
(html, txt)
Предупреждение. Теги замещения в файлах SRF, ссылающиеся на несуществующий атрибут в DLL-библиотеке обработки запросов, вызовут ошибку HTTP 500 Internal Server Error (HTTP 500: внутренняя ошибка сервера). Эту ошибку обнаружить довольно сложно, поскольку она возникает при многих условиях. В Visual Studio .NET отсутствует функция автозавершения, отображающая доступные атрибуты в DLL-библиотеке обработки запросов при изменении разработчиком файла SRF, поэтому велика вероятность неправильного указания тега обработчика запросов.
Мы видим, что листинг исходного кода файла NewSimpleATLServer.srf (см. рис. 4.11) является документом HTML. Единственным различием между файлом HTML и SRF является присутствие тегов, заключенных в парные фигурные скобки ("{{ }}"). Элементы управления сервера, предоставляемых проектами веб-службы или веб-формы, по умолчанию недоступны в проекте сервера ATL. Расширение файла SRF связано с библиотекой расширения ISAPI, поэтому файл HTM, HTML или любой другой файл можно связать с DLL-библиотекой расширения ISAPI и реализовать его обработку так, как если бы речь шла о файле SRF с расширением .srf.
Примечание. Возможность добавления комментариев в файл SRF не столь обширна, как в других типах программных решений (например, в исполняемой программе или веб-службе). Иногда пробелы, размещаемые перед или после тегов замещения, вызывают ошибку в работе файла SRF. Комментарии размещаются перед тегом обработки. Для обозначения тегов используются стили комментариев HTML (!--) или C++ (//). Комментарии нельзя располагать на одной строке с другими тегами, например, с тегами замещения. Например, следующая строка вызовет возврат файлом SRF внутренней ошибки сервера HTTP 500: {{endif // if HaveNameAndColor}}.
Листинг 4.4.
Предупреждение. Теги замещения в файлах SRF, ссылающиеся на несуществующий атрибут в DLL-библиотеке обработки запросов, вызовут ошибку HTTP 500 Internal Server Error (HTTP 500: внутренняя ошибка сервера). Эту ошибку обнаружить довольно сложно, поскольку она возникает при многих условиях. В Visual Studio .NET отсутствует функция автозавершения, отображающая доступные атрибуты в DLL-библиотеке обработки запросов при изменении разработчиком файла SRF, поэтому велика вероятность неправильного указания тега обработчика запросов.
Мы видим, что листинг исходного кода файла NewSimpleATLServer.srf (см. рис. 4.11) является документом HTML. Единственным различием между файлом HTML и SRF является присутствие тегов, заключенных в парные фигурные скобки ("{{ }}"). Элементы управления сервера, предоставляемых проектами веб-службы или веб-формы, по умолчанию недоступны в проекте сервера ATL. Расширение файла SRF связано с библиотекой расширения ISAPI, поэтому файл HTM, HTML или любой другой файл можно связать с DLL-библиотекой расширения ISAPI и реализовать его обработку так, как если бы речь шла о файле SRF с расширением .srf.
Примечание. Возможность добавления комментариев в файл SRF не столь обширна, как в других типах программных решений (например, в исполняемой программе или веб-службе). Иногда пробелы, размещаемые перед или после тегов замещения, вызывают ошибку в работе файла SRF. Комментарии размещаются перед тегом обработки. Для обозначения тегов используются стили комментариев HTML (!--) или C++ (//). Комментарии нельзя располагать на одной строке с другими тегами, например, с тегами замещения. Например, следующая строка вызовет возврат файлом SRF внутренней ошибки сервера HTTP 500: {{endif // if HaveNameAndColor}}.
Завершение работы мастера проекта сервера ATL
По окончании генерирования код проекта ATL Server можно выполнить немедленно. Пока в DLL-библиотеке обработчика запросов находится функция, проект можно скомпилировать и реализовать. Если при генерировании проекта использованы опции мастера по умолчанию, то готовый проект соответствует следующим параметрам:
раздельные библиотеки DLL для расширения ISAPI и для обработчика запросов;во вкладке Server Options (Параметры сервера) не включена ни одна опция;поддержка подтверждения;поддержка обработки шаблона;добавление в код комментариев TODO;код с атрибутами;поддержка особых опций отладки.
Анализ пары "Заголовок-Значение"
После получения заголовка ALL_HTTP из функции GetServerVariable (см. листинг 5.4) для отображения содержимого в XML необходимо реализовать обработку строки. Заголовки разделяются символами новой строки и возврата каретки. Двоеточие (":") разделяет имя заголовка и его значение. GetHeaderValuePair инициализирует поиск в указанной позиции и возвращает имя и соответствующее ему значение для данного заголовка, а также позицию, в которой прерван поиск заголовков. GetHeaderValuePair единовременно осуществляет поиск одного значения заголовка.
Как видно из листинга 5.6 функция GetHeaderValuePair осуществляет поиск символа ":" в HTTP-заголовке, начиная с позиции nStart в строке sHeader. Значение nStart – это счетчик (начинается с нуля). Если символ ":" не найден, функция завершает работу с возвращением значения "ложь". При обнаружении символа ":" (т.е. заголовок существует) в sHeader продолжается поиск новой строки, начиная с позиции, в которой обнаружен данный символ. При поиске используется функция find строки Standard Template Library (STL) с символом новой строки \n в качестве аргумента и с указанием в качестве начальной позиции символа ":". Позиция новой строки становится конечной позицией, возвращаемой указателем pnEnd, посредством чего вызывающей функции становится известно, в каком месте остановлен поиск. С помощью всех параметров позиции, выявленных в процессе вызовов функции поиска строки sHeader, имя заголовка и значение извлекаются в место расположения памяти, связанное с указателями psName и psValue.
Листинг 5.6. Source Code for Function GetHeaderValuePair (html, txt)
Returns data about the search parameters if found or not. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ bool GetHeaderValuePair(const string &sHeader, const int &nStart, string *psName, string *psValue, int *pnEnd) { const string sColon(":");
//determine if header is a post header string::size_type idxColonPosition = nStart;
//start looking at beginning idxColonPosition = sHeader.find(sColon, idxColonPosition);
if (idxColonPosition == string::npos)//no more headers found return false;//this is failure
//get the name psName->assign(sHeader.substr (nStart, idxColonPosition - nStart));
//find next newline string::size_type idxNewLine; idxNewLine = sHeader.find('\n', idxColonPosition);
//get the end even if it means not found *pnEnd = idxNewLine;
if (idxNewLine == string::npos) //a newline was not found return true;//not a failure - might be the last header
//get the value //adjust colon position so we do not assign colon in value idxColonPosition = idxColonPosition +1; psValue->assign(sHeader.substr(idxColonPosition, idxNewLine - idxColonPosition));
return true;
Листинг 5.6. Source Code for Function GetHeaderValuePair
Анатомия URL
URL представляет собой строку, указывающую конкретный ресурс на сервере в интернете. URL формируется согласно следующему синтаксису:
<схема>://<пользователь>:<пароль>@<узел>:<порт>/<url-путь>/<дополнительная информация>
Ниже приведен URL, реализующий запрос файла ISAPI DLL с именем SEUX.dll. В URL указаны параметры parm1 и parm2. В таблице 5.1 данный URL разбит на части, чтобы показать, как определяется обычный URL, осуществляющий запрос библиотеки ISAPI DLL.
http://amd1700v2/simpleisapi/folder1/folder2/SEUX.dll/PATH_INFO? parm1=value1&parm2=value
Многие компоненты URL используются для описания значений серверных переменных, о которых мы поговорим позже. Обратите внимание, что поля, отсутствующие в примере, редко встречаются в URL. В качестве примера приведен наиболее распространенный общий URL.
Если ISAPI DLL запрашивается напрямую через ссылку URL, в секции url-путь определяется имя файла библиотеки DLL расширения ISAPI. В секции URL <дополнительная информация> располагаются пары параметр = значение, передаваемые расширению ISAPI с помощью этой секции или посредством отправки данных HTTP из формы HTML.
Файл экспорта определения
После добавления в проект файла DEF имя библиотеки в файле будет идентично имени проекта (иначе Visual Studio .NET отобразит предупреждение). В нашем проекте имя выглядит следующим образом:
LIBRARY HelloWorld
В файл DEF добавим блок DESCRIPTION для описания назначения библиотеки DLL. Описание заключается в одинарные кавычки. Блок DESCRIPTION не является обязательным в отличие от блока EXPORTS. Имена функций следуют после объявления блока EXPORTS. В листинге 5.1 приведен код файла экспорта определения, использованный в нашем проекте. Функции приводятся в произвольном порядке, однако они должны соответствовать именам в реализации расширения.
Листинг 5.1. HelloWorld.def Content (html, txt)
Функция GetExtensionVersion
Функция GetExtensionVersion использует указатель на структуру HSE_VERSION_INFO в качестве параметра и возвращает значение BOOL в зависимости от того, использует ли IIS расширение ISAPI. Если функция GetExtensionVersion возвращает значение "истина", то расширение ISAPI используется. Функция GetExtensionVersion вызывается при загрузке расширения ISAPI в пространство процесса IIS. После загрузки расширения ISAPI эта функция повторно не вызывается. Она отлично подходит для включения кода, выполняющего проверку ключа лицензии, или для процедур инициализации, проверяющих использование расширения. В листинге 5.2 файла HelloWorld.cpp функция GetExtensionVersion только получает информацию о версии для расширения ISAPI.
Структура HSE_VERSION_INFO содержит две переменные dwExtensionVersion и lpszExtensionDesc. Этим переменным присваиваются значения при вызове функции GetExtensionVersion. В листинге 5.2 переменной dwExtensionVersion присваивается значение 0,9 типа DWORD, а переменной lpszExtensionDesc – значение HelloWorld. Эта функция всегда возвращает значение "истина", так как в IIS всегда загружается расширение ISAPI. Если расширение ISAPI зависит от наличия действительного файла лицензии, другой программной библиотеки или специальной конфигурации, тогда в функции можно выполнять соответствующую проверку и возвращать значение "ложь" в случае отрицательного результата.
Функция GetServerVariable
Функция GetServerVariable возвращает значение "истина" при успешном выполнении и значение "ложь" при возникновении ошибки, как показано в следующем примере:
BOOL WINAPI GetServerVariable( HCONN hConn, LPSTR lpszVariableName, LPVOID lpvBuffer, LPDWORD lpdwSizeofBuffer );
Прототип GetServerVariable в данном случае требует передачи четырех параметров.
hConn. Поддержка соединения, полученная от ECB.lpszVariableName. Строка с символом конца строки запрашиваемой серверной переменной.lpvBuffer. Пустой указатель на буфер, который заполняется результирующим значением имени переменной и байтом конца строки.lpdwSizeofBuffer. Указатель на значение DWORD, отражающее размер буфера.
При успешном выполнении функция GetServerVariable возвращает значение "истина". Указатель lpvBuffer указывает значение запрашиваемой серверной переменной, а lpdwSizeofBuffer – на новое значение DWORD, отражающее текущий размер значения, включая байт конца строки. При неудачном завершении работы функция GetServerValue возвращает значение "ложь". В этом случае вызывается функция GetLastError, которая возвращает значение DWORD, представляющее собой код ошибки. В таблице 5.2 показаны возможные ошибки функции GetServerVariable; это константы, определяемыми во вспомогательном файле заголовка расширения ISAPI.
Функция HttpExtensionProc
Функция HttpExtensionProc в качестве параметра использует одну из важнейших структур ISAPI – блок контроля расширения (Extension Control Block, ECB). Эта структура содержит следующие компоненты:
данные о запросе HTTP;данные веб-экземпляра IIS, через которое поступил запрос;вспомогательные функции для анализа запроса HTTP;вспомогательные функции для управления ответом HTTP.
Изучая код листинга 5.2, следует отметить, что указатель на блок ECB используется только для отправки заголовка ответа клиенту и для отображения клиенту фразы "Hi! Hello World". Код C++ похож на C в структурах и вспомогательных функциях, поскольку ISAPI не сильно изменился со времени выхода первой версии IIS для обеспечения обратной совместимости. Заметным изменениям ISAPI стало добавление новых функциональных возможностей. Трудность работы с ISAPI состоит в том, что некоторые API требуют программирования с использованием решений языка C.
Первой функцией, вызываемой в блоке ECB расширения HelloWorld, является функция ServerSupportFunction. Она устанавливает заголовок в ответе HTTP для обозначения вида содержимого (текст или HTML) с помощью следующей строки:
Content-type: text/html\r\n\r\n
За заголовками ответов HTTP должны следовать две пары символов возврата каретки и перехода на новую строку (/n и /r).
Следующей функцией, вызываемой с помощью ECB, является функция WriteClient. Фраза "Hi! Hello World" записывается в браузер с помощью данной функции посредством передачи указателя char (char*) строковой переменной, содержащей код HTML и строку "Hi! Hello World". Функции WriteClient нужен пустой указатель (void*), поэтому указатель char приводится к форме пустого указателя с помощью макроса PVOID.
Главная точка входа расширения ISAPI
Файл HelloWorld.cpp необходимо настроить на поддержку функций, необходимых для обеспечения работы расширения ISAPI.
В Visual Studio .NET откройте файл HelloWorld.cpp для редактирования посредством двойного щелчка на имени файла в окне Solution Explorer.Удалите функцию DLLMain (она не нужна в данном примере).В верхней части файла с кодом добавьте препроцессорную директиву включения для файла заголовка httpext.h и <string> (см. листинг 5.2).Добавьте функцию GetExtensionVersion (см. листинг 5.2).Добавьте функцию HttpExtensionProc (см. листинг 5.2).
Листинг 5.2. Source Code for HelloWorld.cpp (html, txt)
Purpose: main entry point for HTTP request
the possible return codes are: HSE_STATUS_SUCCESS - everything worked great HSE_STATUS_SUCCESS_AND_KEEP_CONN - same as HSE_STATUS_SUCCESS since IIS 4 HSE_STATUS_PENDING - wait until effort completed HSE_STATUS_ERROR - sends a 500 error code /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB) { //HTTP headers const char* BASIC_HEADER = "Content-type: text/html\r\n\r\n"; //output values const DWORD BUFFER_LENGTH = 4096; TCHAR szTempBuffer[BUFFER_LENGTH]; DWORD dwBufferSize = BUFFER_LENGTH; string sResponse;
//start our HTML document sResponse = "<HTML><HEAD></HEAD><BODY><P>"; sResponse += "Hi! Hello World"; sResponse += "</P></BODY></HTML>";
// set content-type header strcpy(szTempBuffer, BASIC_HEADER); DWORD dwHeaderSize = strlen(szTempBuffer); pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, &dwHeaderSize, (LPDWORD) szTempBuffer);
//write value to http response DWORD dwLength=sResponse.length(); pECB->WriteClient( pECB->ConnID, (PVOID)sResponse.c_str(), &dwLength, 0);
//return a success code return HSE_STATUS_SUCCESS; }
Листинг 5.2. Source Code for HelloWorld.cpp
Извлечение информации из IIS
ECB обычно используется для извлечения информации о запросе HTTP и экземпляре сервера IIS, посредством чего расширение ISAPI выполняет определенные программные действия на основе события запроса. В коде листинга 5.3, взятого из расширения ISAPI SEUX (Простое расширение с использованием XML), функция HttpExtensionProc выполняет следующие задачи.
Построение документа XML со множеством общих серверных переменных, получаемых из функции GetServerVariable.Добавление свойств ECB в документ XML.Возврат документа XML запрашивающей стороне.
Листинг 5.3. HttpExtensionProc Function Building XML Document in SEUX ISAPI Extension (html, txt)
Примечание. Исходный код SEUX доступен на веб-сайте автора книги (см. введение).
// End THE ECBServerVariable VARIABLES sDoc += string(XML_L_END) + string("ECBServerVariable") + string(XML_R) + string(NEW_LINE);
//START THE ECBProperties sDoc += string(XML_L) + string("ECBProperties") + string(XML_R) + string(NEW_LINE);
GetElement(string("lpszLogData"), string(pECB->lpszLogData),&sDoc); GetElement(string("lpszMethod"), string(pECB->lpszMethod),&sDoc); GetElement(string("lpszQueryString"), string(pECB->lpszQueryString),&sDoc); GetElement(string("lpszPathInfo"), string(pECB->lpszPathInfo),&sDoc); GetElement(string("lpszContentType"), string(pECB->lpszContentType),&sDoc);
//end THE ECBProperties sDoc += string(XML_L_END) + string("ECBProperties") + string(XML_R) + string(NEW_LINE);
//end our XML document sDoc += string(XML_L_END) + string(MAIN_ELEMENT_NAME) + string(XML_R) + string(NEW_LINE);
//write it! SendResponse(pECB,sDoc);
return HSE_STATUS_SUCCESS; }
Листинг 5.3. HttpExtensionProc Function Building XML Document in SEUX ISAPI Extension
Примечание. Исходный код SEUX доступен на веб-сайте автора книги (см. введение).
Мастер шаблона проекта ISAPI
При создании расширения ISAPI с использованием поддержки MFC воспользуйтесь мастером шаблона проекта ISAPI (ISAPI Project Template Wizard). Мастер настроит проект на необходимую поддержку для библиотек ISAPI и создаст класс, унаследованный из CHttpServer. Для ISAPI предоставляются следующие классы MFC.
CHttpArgList. Класс, содержащий функции и структуры для анализа URL.CHtmlStream. Класс, управляющий памятью по отношению к данным, предназначенных для передачи клиенту.CHttpFilter. Класс, расширяющий интерфейс IIS для создания фильтра ISAPI. Фильтры представляют собой тип приложения ISAPI, вызываемый при каждом запросе IIS, поэтому они отвечают на события внутри IIS.CHttpFilterContext. Класс, являющийся параметром в функциях класса CHttpFilter, для обработки содержимого данного события HTTP. Служит для обработки связанных с рассматриваемым событием HTTP данных, проходящих через фильтр.CHttpServer. Класс, расширяющий интерфейс IIS для рассматриваемого события HTTP-запроса.ChttpServerContext. Класс, обеспечиваемый классом CHttpServer, содержащий методы управления данными, связанными с рассматриваемым событием HTTP.
Классы, предоставляемые в MFC, обеспечивают хороший уровень абстракции для первоначального взаимодействия со структурами ISAPI и функциями, приведенными выше. С помощью MFC разработчик осуществляет доступ к "сырому" ISAPI. Некоторые классы облегчают анализ заголовков и данных HTTP, выполняемый вручную в расширении ISAPI SEUX. Мастер создаст класс, которому будет присвоено имя согласно следующей схеме: C<Имя_проекта>Расширение. Функция с именем Default является главной точкой входа для ISAPI DLL:
void Default(CHttpServerContext* pCtxt);
Функция Default заменяет функцию HttpExtensionProc, используемую в расширении ISAPI SEUX в качестве главной точки входа. Указатель на класс CHttpServerContext, передаваемый в функцию Default, обеспечивает функциональность и требования разработчика к управлению данными и HTTP-транзакцией (осуществлялось посредством ECB в расширении ISAPI SEUX).
Обзор архитектуры ISAPI
Приложения ISAPI представляют собой библиотеки DLL, напрямую взаимодействующие с IIS API. Программное обеспечение ISAPI – это расширение или фильтр. Расширения ISAPI являются библиотеками DLL, вызываемыми посредством квалифицированного запроса в IIS. Фильтры ISAPI вызываются независимо от других запросов IIS. Запросы HTTP передаются напрямую расширению ISAPI с помощью ссылки URL или данных, отправляемых из формы HTML. Расширение ISAPI может вызываться косвенно посредством связывания файла с определенным расширением ISAPI в IIS. При установке связей файлов выполняются действия, аналогичные ассоциированию файлов ответа сервера (SRF) с конкретным расширением ISAPI в ATL Server (см. лекцию 4). Можно настроить реагирование фильтров ISAPI на запросы согласно приоритету; это отличает их от других фильтров, загружаемых в IIS. Фильтры используются в специализированных приложениях, связанных с IIS, и обычно выполняют следующие задачи:
шифрование;ведение журналов;аутентификация;сжатие данных.
Расширения ISAPI – наиболее частый способ применения ISAPI. Фильтры ISAPI довольно сложны в создании, и сфера их использования ограничена. Данная тема выходит за рамки книги и рассматриваться не будет.
Построение остальных элементов XML
После обработки функции HttpExtensionProc значения заголовка ALL_HTTP остальные серверные переменные обрабатываются с помощью функции GetECBElement (см. листинг 5.7). Каждая серверная переменная, передаваемая в GetECBElement, извлекается с помощью функции GetServerVariable и записывается в элемент XML, присоединяемый к строке, на которую указывает psElement. Указатель psElement указывает на документ XML, конструируемый в HttpExtensionProc.
Листинг 5.7. Function GetECBElement (html, txt)
Функция ValidateValue проверяет, что специальные символы указаны с помощью альтернативных комбинаций символов. Функция применяется к строке, перед тем как строке присваивается статус значения элемента. Для подтверждения значения атрибута можно применять ValidateValue. XML не разрешает использование определенных специальных символов в позиции значения, если они не представлены в альтернативном виде. Как видно из листинга 5.8, символы, используемые для реализации XML-структуры: "=", "?" и "?" – заменяются альтернативными эквивалентами.
Листинг 5.8. Function ValidateValue (html, txt)
Функция FindAndReplace представляет собой утилиту для замещения всех вхождений строки. В расширении ISAPI SEUX она является идеальным механизмом для замещения одной фразы внутри строки другой фразой. Аргументы представляют собой указатели на строки:
изменяемая строка (контейнер);строка, которую нужно заменить внутри контейнера (цель);строка, заменяющая цель в контейнере (замещение).
Строка STL содержит функции find и replace, используемые функцией FindAndReplace для поиска контейнера всех вхождений цели (см. листинг 5.9). Каждый раз при обнаружении цели в контейнере происходит ее замена, и начинается новый поиск. По завершении работы функции FindAndReplace контейнер обновляется замещениями, если таковые имеются.
Листинг 5.9.
(html, txt)
Функция GetElement работает аналогично функции GetECBElement; она вызывается из функции HttpExtensionProc для конкатенации элементов из свойств ECB.
Свойства извлекаются из ECB, после чего передаются вместе со своими именами и документом XML в функцию GetElement. GetElement размещает свойство ECB и соответствующее значение в XML документе и конкатенирует его с указателем документа XML, переданным функции GetElement. Осуществляется запрос следующих свойств:
lpszLogData. Буфер размера HSE_LOG_BUFFER_LEN, используемый для размещения информации, добавляемой в файл журнала для данной транзакции HTTP-запроса.lpszMethod. Строковое значение используемого метода HTTP, например, GET, PUT или HEAD.lpszQueryString. Строковое значение символов в секции дополнительной информации адреса URL, исключая символ "?". Аналогично значению переменной сервера QUERY_STRING.lpszPathInfo. Строковое значение секции URL, находящейся между библиотекой DLL расширения ISAPI и началом секции дополнительной информации URL. Обычно не содержит данных, если запрашивающее ПО не разместило в этом месте определенное значение.lpszContentType. Строковое значение типа содержимого отправленных по HTTP данных. Аналогично значению серверной переменной CONTENT_TYPE.
Когда функция HttpExtensionProc завершает получение содержимого всех возможных серверных переменных и свойств ECB, в документе XML указываются закрывающие тегов XML, и он передается функции SendResponse. SendResponse направляет запрашивающей программе строковое значение, переданное в функцию. Заголовок типа содержимого передается запрашивающему клиенту с помощью функции ECB ServerSupportFunction (см. листинг 5.10). Передаваемый заголовок представляется константой BASIC_HEADER, эквивалентной следующей строке: Content-type: text/html\r\n\r\n. За заголовками HTTP следуют два символа возврата каретки и новой строки, поскольку возвращаемые данные представляют собой текст. Можно указать и XML, однако если в запрашивающем браузере в XML зарегистрированы типы Multipurpose Internet Mail Extensions (MIME), то для отображения XML откроется зарегистрированная программа.
Листинг 5.10. Function SendResponse (html, txt)
После отправки заголовка возврата отправляется содержимое с помощью функции WriteClient. Как показано в следующем примере, при передаче данных клиенту отправляется идентификатор соединения ConnID. Имеющееся значение, полученное из текущего экземпляра указателя, использовано в листинге 5.10. Содержимое передается функцией WriteClient с помощью пустого указателя в параметре Buffer. Содержимое, на которое ссылается указатель Buffer, должно равняться количеству байт, передаваемому клиенту, и указываться в параметре lpdwBytes. По завершении вызова lpdwBytes содержит количество переданных байт, если запись не осуществлялась асинхронно. Значение параметра dwSync определяет способ передачи данных клиенту. В листинге 5.10 с помощью макроса HSE_IO_SYNC указывается значение 0х00000001, т.е. запись выполняется синхронно, и пространство памяти, на которое ссылается указатель lpdwBytes, обновится по завершении WriteClient количеством байт, переданным клиенту. Если в макросе HSE_IO_ASYNC представлено значение 0х00000002, то данные, отправляемые клиенту, и функция обратной связи зафиксируют события передачи информации клиенту. Асинхронное использование функции WriteClient требует объявления функции обратной связи, а также отправки функцией ServerSupportFunction значения HSE_REQ_IO_COMPLETION для установки с клиентом транзакции асинхронной записи.
Функция WriteClient является членом ECB. Может показаться странным, что используемое описание ECB передается функции. Поскольку приложение IIS включает несколько нитей, в любой момент времени может потребоваться несколько экземпляров ECB, и вероятно выполнение записи в экземпляре ECB в другой экземпляр ECB. Ниже приведен пример WriteClient:
BOOL WriteClient( HCONN ConnID, LPVOID Buffer, LPDWORD lpdwBytes, DWORD dwSync );
Аналогично значению переменной сервера QUERY_STRING.lpszPathInfo. Строковое значение секции URL, находящейся между библиотекой DLL расширения ISAPI и началом секции дополнительной информации URL. Обычно не содержит данных, если запрашивающее ПО не разместило в этом месте определенное значение.lpszContentType. Строковое значение типа содержимого отправленных по HTTP данных. Аналогично значению серверной переменной CONTENT_TYPE.
Когда функция HttpExtensionProc завершает получение содержимого всех возможных серверных переменных и свойств ECB, в документе XML указываются закрывающие тегов XML, и он передается функции SendResponse. SendResponse направляет запрашивающей программе строковое значение, переданное в функцию. Заголовок типа содержимого передается запрашивающему клиенту с помощью функции ECB ServerSupportFunction (см. листинг 5.10). Передаваемый заголовок представляется константой BASIC_HEADER, эквивалентной следующей строке: Content-type: text/html\r\n\r\n. За заголовками HTTP следуют два символа возврата каретки и новой строки, поскольку возвращаемые данные представляют собой текст. Можно указать и XML, однако если в запрашивающем браузере в XML зарегистрированы типы Multipurpose Internet Mail Extensions (MIME), то для отображения XML откроется зарегистрированная программа.
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Name: SendResponse
In: pECB - pointer to the extension control block sValue - string reference to the value to be written to the HTTP response
Out: nothing
Purpose: writes the intended value to the HTTP response /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ void SendResponse(EXTENSION_CONTROL_BLOCK *pECB, string &sValue) { TCHAR szTempBuffer[BUFFER_LENGTH]; DWORD dwBufferSize = BUFFER_LENGTH;
// set content-type header strcpy(szTempBuffer, BASIC_HEADER); DWORD dwHeaderSize = strlen(szTempBuffer); pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, &dwHeaderSize, (LPDWORD) szTempBuffer);
// write value to http response DWORD dwLength=sValue.length(); pECB->WriteClient( pECB->ConnID, (PVOID)sValue.c_str(), &dwLength, HSE_IO_SYNC); }
Листинг 5.10. Function SendResponse
После отправки заголовка возврата отправляется содержимое с помощью функции WriteClient. Как показано в следующем примере, при передаче данных клиенту отправляется идентификатор соединения ConnID. Имеющееся значение, полученное из текущего экземпляра указателя, использовано в листинге 5.10. Содержимое передается функцией WriteClient с помощью пустого указателя в параметре Buffer. Содержимое, на которое ссылается указатель Buffer, должно равняться количеству байт, передаваемому клиенту, и указываться в параметре lpdwBytes. По завершении вызова lpdwBytes содержит количество переданных байт, если запись не осуществлялась асинхронно. Значение параметра dwSync определяет способ передачи данных клиенту. В листинге 5.10 с помощью макроса HSE_IO_SYNC указывается значение 0х00000001, т.е. запись выполняется синхронно, и пространство памяти, на которое ссылается указатель lpdwBytes, обновится по завершении WriteClient количеством байт, переданным клиенту. Если в макросе HSE_IO_ASYNC представлено значение 0х00000002, то данные, отправляемые клиенту, и функция обратной связи зафиксируют события передачи информации клиенту. Асинхронное использование функции WriteClient требует объявления функции обратной связи, а также отправки функцией ServerSupportFunction значения HSE_REQ_IO_COMPLETION для установки с клиентом транзакции асинхронной записи.
Функция WriteClient является членом ECB. Может показаться странным, что используемое описание ECB передается функции. Поскольку приложение IIS включает несколько нитей, в любой момент времени может потребоваться несколько экземпляров ECB, и вероятно выполнение записи в экземпляре ECB в другой экземпляр ECB. Ниже приведен пример WriteClient:
BOOL WriteClient( HCONN ConnID, LPVOID Buffer, LPDWORD lpdwBytes, DWORD dwSync );
Построение простого расширения ISAPI
Расширения ISAPI имеют такую несложную структуру, что могут создаваться без помощи MFC или ATL. Расширение ISAPI можно написать, используя файл включения расширения httpext.h и файл DLL definition export file (DEF) с экспортом двух следующих функций:
HttpExtensionProc; GetExtensionVersion.
Каждое расширение ISAPI должно поддерживать эти функции. Оно может также экспортировать функцию TerminateExtension (это не является обязательным). После настройки проекта DLL расширение нужно применить к IIS. В Visual Studio .NET имеется шаблон проекта ISAPI, запускающий мастер расширения ISAPI. Этот мастер создает класс, названный по имени проекта, наследуемый из класса CHTTPServer и содержащий необходимые функции ISAPI. Мастер расширения ISAPI использует файлы заголовков для поддержки от MFC, ATL и httpext.h для получения классов и структур ISAPI.
Работа с мастером расширения ISAPI будет описана позже. Рассмотрим метод создания простого расширения ISAPI с минимальной поддержкой MFC и ATL без помощи мастера.
В Visual Studio .NET выберите команду File\New\Project (Файл\Создать\Проект) для открытия диалогового окна New Project (Новый проект).
В диалоговом окне New Project (Новый проект) щелкните на узле Visual C++ Projects (Проекты Visual C++) в левой части окна и выберите шаблон проекта Win32. Присвойте проекту имя HelloWorld и выберите место расположения создаваемого проекта.
При нажатии на кнопку More (Больше) диалоговое окно New Project (Новый проект) отобразит дополнительную информацию о том, в каком месте будет создан проект. Название данной кнопки изменится на Less (Меньше). По умолчанию Visual Studio создает каталог с именем, идентичным имени проекта, в папке, указанной в текстовом поле Location (Расположение), в котором располагаются все файлы проекта. На рисунке 5.2 показано, что в текстовом поле Location (Расположение) введено значение C:\bookMaterial\IISBook\17ISAPIExtension\code, а именем проекта является HelloWorld.
Рис. 5.2. Диалоговое окно New Project (Новый проект) с выбранным проектом Win32
Нажмите на кнопку OK для запуска мастера приложений Win32 (Win32 Application Wizard) (см. рис. 5.3).
Рис. 5.3. Обзор в мастере приложения Win32
Откройте вкладку Application Settings (Параметры приложения) в левой части мастера приложений Win32.Выберите DLL в качестве типа приложения (см. рис. 5.4).
Рис. 5.4. Создание проекта Win32 DLL.
Нажмите на кнопку Finish (Готово); Visual Studio создаст каталог C:\bookMaterial\IISBook\17ISAPIExtension\code\HelloWorld и разместит в нем файлы проекта.Выберите команду Project\Properties (Проект\Свойства) для открытия окна свойств страницы.Выберите в левой части окна свойств узел Precompiled Header в узле C/C++ для отображения свойств проекта.Visual Studio .NET не имеет шаблона проекта, который реализуется без заранее скомпилированного заголовка, поэтому выберите шаблон проекта Win32, создайте из проекта библиотеку DLL и удалите параметр заранее скомпилированного заголовка. В ниспадающем списке Create\Use Precompiled Header (Создать\Использовать готовый заголовок) выберите Not Using Precompiled Headers (Не использовать готовые заголовки) в ниспадающем списке Create\Use Precompiled Header (Создать\Использовать готовый заголовок) (см. рис. 5.5).
увеличить изображение
Рис. 5.5. Изменение параметра готового заголовка проекта
Нажмите на кнопку OK в окне свойств. Откроется окно Solution Explorer (Обозреватель решения); если это не так, то выберите в меню команду View\Solution Explorer (Вид\Обозреватель решения).Готовый заголовок не используется, поэтому удалите файлы stdafx, созданные Visual Studio .NET для его поддержки. В окне Solution Explorer выделите заголовок stdafx и файлы реализации, щелкните правой кнопкой мыши и выберите Remove (Удалить) (см. рис. 5.6).
Рис. 5.6. Удаление файлов stdafx из проекта
Теперь нужно добавить в проект DEF. Для этого щелкните правой кнопкой мыши на имени проекта в Solution Explorer и выберите команду Add\Add New Item (Добавить\Добавить новый элемент).В диалоговом окне Add New Item (Добавление нового элемента) выделите DEF File (Файл DEF) и присвойте файлу имя Hello World в соответствии с именем проекта (см.
рис. 5.7). Имя файла должно соответствовать имени DLL, иначе компилятор C++ отобразит предупреждение о несоответствии имен файлов. Рассматриваемый файл DEF (файл экспорта определения) описывает функции, экспортируемые из DLL, чтобы другое приложение могло загрузить DLL и найти адреса функций.
Рис. 5.7. Добавление в проект файла экспорта определения
Нажмите на кнопку Open (Открыть) в диалоговом окне Add New Item (Добавить новый элемент) для добавления в проект нового файла DEF.
Шаблоны проекта Visual Studio используют встроенный механизм MFC для экспорта функций и использования библиотеки DLL расширения ISAPI программой-потребителем, каковой является IIS. В Visual Studio .NET нет шаблона проекта, создающего конечный продукт без готового заголовка, поэтому следует выбрать шаблон проекта Win32, преобразовать его в DLL, после чего удалить ненужные файлы и настройки. При создании проекта без поддержки MFC иногда возникают некоторые сложности. Однако MFC сами по себе достаточно сложны, поэтому небольшие проекты (как в нашем примере) можно упростить, отказавшись от использования MFC.
Следующим шагом является настройка файла DEF.
Построение XML для представления значений серверных переменных
Первой задачей (см. листинг 5.3) является открытие документа XML посредством присоединения некоторых констант, представляющих собой части документа XML. Построение XML происходит вручную, и константы объявляются для общих частей документа XML, так как они используются во многих местах. Документ XML размещается в строковой переменной с именем sDoc. Ниже приведены константы XML:
//xml parts const char* MAIN_ELEMENT_NAME = "HTTPRequestRaw"; const char* QUOTE ="\""; const char* XML_L ="<"; const char* XML_R =">"; const char* XML_L_END ="</"; const char* XML_R_END ="/>"; const char* NEW_LINE ="\n"; const char* HEAD = "<?xml version=\"1.0\"?>";
Рассматриваемый документ XML достаточно прост, поэтому его построение вручную не вызывает никаких трудностей. Для более сложного документа рекомендуется использовать аналитическую библиотеку XML, такую как MSXML.
После инициализации документа XML начинается работа по размещению в элементах XML всех серверных переменных. Создаваемый документ XML имеет родительский элемент HTTPRequestRaw. Внутри HTTPRequestRaw содержатся два дочерних элемента с ECBServerVariable и ECBProperties. Для каждого значения серверной переменной, запрашиваемого из ECB, будет создаваться дочерний элемент для элемента ECBServerVariable, независимо от получения значения соответствующей серверной переменной. Для каждого запрошенного свойства ECB создается дочерний элемент под элементом ECBProperties, которое содержит значение независимо от получения значения свойства. При вызове расширения ISAPI SEUX с помощью IE 6.0 отобразится документ XML (см. рис. 5.12). В других версиях браузера XML может отобразится по-другому или не отобразиться вовсе.
увеличить изображение
Рис. 5.12. IE 6.0, отображающий документ XML серверных переменных из расширения SEUX ISAPI
Расширения ISAPI во взаимодействии с IIS
Если IIS получает запрос и считает, что необходимо использовать расширение ISAPI (запрошен файл, связанный с расширением ISAPI или само расширение ISAPI), то IIS передает запрос HTTP вместе с расширением ISAPI. Чтобы расширение ISAPI получило запрос HTTP, используется определенный программный интерфейс. Как известно, приложение ISAPI содержит файлы заголовков ISAPI, определяющих структуры и классы. Расширение ISAPI примет запрос посредством используемого интерфейса API, и данные запроса HTTP будут загружены в структуры и классы, являющиеся компонентами ISAPI.
схема | http |
пользователь | Отсутствует в демонстрационном URL |
пароль | Отсутствует в демонстрационном URL |
узел | amd1700v2 |
порт | Отсутствует в демонстрационном URL (подразумевается значение 80) |
url-путь | simpleisapi/folder1/folder2/SEUX.dll/PATH_INFO |
дополнительная информация | ?parm1=value1&parm2=value |
Расширение ISAPI анализирует данные HTTP-запроса и направляет вызовы другому программному обеспечению, например, программе бизнес-уровня (см. рис. 5.1). Ответы этой программы формируются в виде HTTP-ответов и возвращаются в IIS. IIS возвращает ответ расширения ISAPI веб-пользователю, направившему изначальный запрос.
Рис. 5.1. Обзор архитектуры расширения ISAPI
Архитектура, показанная на рисунке 5.1, позволяет использовать расширения ISAPI двумя возможными способами, но не является единственным вариантом технологии. Единственным ограничением является вызов расширения ISAPI при HTTP-запросе и наличие структур и классов, содержащих HTTP-запрос и поддерживающих программное взаимодействие с ответом HTTP и запросом HTTP. Построение абстракции логики – задача разработчика. Направление вызовов библиотеке бизнес-логики необязательно, если бизнес-логика заключена в самом расширении ISAPI. Так как ISAPI напрямую записывает данные в HTTP-запрос, следует создавать архитектуру, абстрагирующую логику представления для исключения повторной компиляции ISAPI DLL при изменении логики представления.
Реализация ISAPI "HelloWorld"
После успешной компиляции DLL расширение ISAPI можно отгружать на веб-сервер. Если в качестве расположения конечного файла DLL указан экземпляр веб-сервера или корень виртуального каталога, можно немедленно запросить файл из IIS. При выполнении отладки Visual Studio .NET браузер не откроется, и автоматического запроса ISAPI DLL из IIS (как при отладке веб-службы ASP.NET) не произойдет. Visual Studio считает проект библиотекой DLL, поэтому выдаст запрос на присвоение исполняемого файла, который использует данную библиотеку.
Запомните. Если разработчик осуществляет построение библиотеки DLL расширения ISAPI и затем тестирует DLL посредством ее запроса через IIS, при втором построении ISAPI DLL в Visual Studio .NET, скорее всего, не удастся создать DLL. IIS блокирует библиотеку DLL расширения ISAPI при ее запросе из IIS, поскольку DLL загружается в пространство процесса IIS. Для разблокирования ISAPI DLL необходимо выгрузить экземпляр веб-сайта или виртуального каталога либо заново запустить приложение. После разблокирования ISAPI DLL поверх нее в процессе построения осуществляется запись.
При первом запросе ISAPI DLL из IIS 6 в операционной системе Windows Server 2003, скорее всего, возвратится ошибка 404. В WS03 и IIS6 существует новая возможность, ограничивающая по умолчанию всякую программную поддержку серверной части, если она не включена вручную. В предыдущих версиях Windows Server компонент IIS поставлялся с включенной программной поддержкой серверной части (ASP). Эта функция включается в окне Web Service Extensions (Расширения веб-служб) консоли MMC Computer Management (Управление компьютером) (см. рис. 5.8).
увеличить изображение
Рис. 5.8. Включение программной функциональности серверной части в окне Web Service Extensions (Расширения веб-служб)
Настроим IIS на разрешение запросов расширения ISAPI HelloWorld.
В окне администрирования расширения веб-служб щелкните на ссылке Add A New Web Service Extension (Добавить новое расширение веб-службы).
Откроется диалоговое окно New Web Service Extension (Новое расширение веб-службы).В текстовом поле Extension Name (Имя расширения) введите имя, которое будет отображаться в окне администрирования расширения веб-служб. В нашем примере это имя HelloWorld (см. рис. 5.9).
Рис. 5.9. Диалоговое окно New Web Service Extension (Новое расширение веб-службы)
Нажмите на кнопку Add (Добавить), чтобы указать путь к файлу расширения ISAPI. Откроется диалоговое окно Add File (Добавление файла), в котором вручную вводится путь к файлу, либо укажите его расположение в окне Open File (Открыть файл) после нажатия на кнопку Browse (Обзор).Установите путь к файлу расширения ISAPI, затем нажмите на кнопку OK в диалоговом окне Add File (Добавление файла). Файла расширения ISAPI отобразится в диалоговом окне New Web Service Extension (Новое расширение веб-службы).Отметьте опцию Set Extension Status To Allowed (Разрешить использование расширения), после чего нажмите на кнопку OK.
Расширение HelloWorld появится в окне администрирования расширения веб-служб консоли Copmuter Management (Управление компьютером), и в поле Status (Состояние) отобразится значение Allowed (Разрешено).
В качестве альтернативы установите Allowed (Разрешено) для расширения веб-службы All Unknown ISAPI Extensions (Все неизвестные расширения ISAPI). Данный параметр разрешает выполнение любого запроса относительно любого расширения ISAPI.
Включение данной настройки нарушает безопасность сервера, поэтому используйте этот параметр только в изолированных средах, таких как среда разработки.
Разрешения на выполнение веб-экземпляра IIS или виртуального каталога устанавливаются на разрешение выполнения библиотек ISAPI DLL. По умолчанию параметр Execute Permissions (Разрешения на выполнение) в окне свойства веб-экземпляра IIS или виртуального каталога не позволяет выполнять сценарии и исполняемые файлы.
Откройте оснастку IIS MMC Computer Management (Управление компьютером) и щелкните правой кнопкой мыши на веб-экземпляре или виртуальном каталоге для отображения контекстного меню.Выберите Properties (Свойства) для открытия окна свойств веб-экземпляра или виртуального каталога.Во вкладке Virtual Directory (Виртуальный каталог) окна свойств виртуального каталога или во вкладке Home Directory (Домашний каталог) веб-экземпляра расположено поле со списком Execute Permissions (Разрешения на выполнение) (см.рис. 5.10). Убедитесь, что отмечена опция Scripts And Executables (Сценарии и исполняемые файлы).
Рис. 5.10. Установка разрешений для виртуального каталога
Если в IIS все настроено должным образом, ISAPI Hello World будет функционировать. Запросите библиотеку ISAPI DLL в адресе URL из браузера, как если бы это был файл HTML – и DLL выполнится (см. рис. 5.11).
Рис. 5.11. Выполнение расширения ISAPI HelloWorld
Создание расширения ISAPI в Visual Studio .NET
Для создания расширения ISAPI с помощью шаблона проекта Vusal Studio .NET откройте Visual Studio .NET и выберите File\New\Project (Файл\Создать\Проект). Откроется диалоговое окно New Project (Новый проект) (см. рис. 5.13). Выберите шаблон проекта MFC ISAPI Extension DLL, введите имя проекта и нажмите на кнопку OK.
Рис. 5.13. Выбор шаблона проекта MFC ISAPI Extension DLL в Visual Studio .NET
Примечание. Диалоговое окно (см. рис. 5.13) отображает значки, отличающиеся от тех, которые показаны на рис. 5.2. В обоих случаях использованы одинаковые версии Visual Studio .NET. Рисунок 5.2 получен при нажатии на кнопку Large Icons (Большие значки) в правом верхнем углу, рисунок 5.13 – при нажатии на кнопку Small Icons (Мелкие значки). Кнопки Large Icons (Большие значки) и Small Icons (Мелкие значки) являются взаимоисключающими, и они влияют на отображение значков проекта в правой части диалогового окна New Project (Новый проект).
По аналогии с мастером проекта сервера ATL (см. лекцию 4) работа мастера расширения ISAPI выполняется в одном окне, и его работа завершается после нажатия на кнопку Finish (Готово) (см. рис. 5.14). Мастер приводит обзор параметров проекта в области Overview (Обзор). Типом создаваемого проекта по умолчанию является библиотека DLL расширения ISAPI с MFC в общей DLL. Данные настройки подходят для большинства проектов ISAPI. Эти параметры можно изменить в области Object Settings (Параметры объекта).
Рис. 5.14. Область Overview (Обзор) мастера расширения ISAPI с проектом ISAPI по умолчанию
В области Object Settings (Параметры объекта) настраиваются имена классов, сгенерированных мастером, содержатся опции, позволяющие расширению ISAPI подключаться к MFC статически или динамически. Выбор опции Use MFC In A Shared DLL (Использовать MFC в общей DLL) (см. рис. 5.15) определяет динамическое подключение MFC в ISAPI DLL, генерируемой во время компиляции. Подразумевается, что MFC существует в среде разработки, что достигается исключением содержимого из ISAPI DLL.
Рис. 5.15. Область Object Settings ( Параметры объекта) мастера расширения ISAPI с проектом ISAPI по умолчанию.
При выборе опции Use MFC In A Static Library (Использовать MFC в статической библиотеке) компоненты MFC компилируются в DLL и подключаются статически. В этом случае подразумевается, что MFC не существует в среде разработки. Размер библиотеки при статическом подключении больше, чем при динамическом подключении. В большинстве случаев MFC располагаются в целевой среде, так как речь идет о сервере Windows. Для WS03 используйте динамическое подключение, поскольку MFC находятся на сервере.
Можно сгенерировать объект фильтра, включив опцию Generate A Filter Object (Генерировать объект фильтра). Фильтры загружаются в IIS для обработки каждого запроса, имеющего место в IIS. Они работают по аналогии с расширением ISAPI, как если бы оно было связано с каждым файлом корневого веб-каталога. Фильтр и расширение не являются взаимоисключающими функциями. Одна библиотека DLL может содержать как расширение, так и фильтр, что позволяет каждому из этих объектов использовать состояние посредством глобальных переменных.
Фильтры ISAPI сложны для разработки и тестирования. Они вызываются при каждом запросе в IIS, поэтому необходимо обеспечить их эффективность и правильность построения. Фильтры могут снизить эффективность сервера или вызвать сбой в его работе при возникновении проблем с памятью.
После нажатия на кнопку Finish (Готово) и завершения мастером генерации файлов проект можно скомпилировать и запустить, как только библиотека DLL будет отгружена на сервер. Если все выполнится правильно, вы увидите в браузере сообщение, имя класса в котором соответствует выбранному имени класса:
This default message was produced by the Internet Server DLL Wizard. Edit your CMFCISAPIExtension::Default() implementation to change it.
Специальный случай серверной переменной ALL_HTTP
Первой серверной переменной, для которой получается значение, является переменная ALL_HTTP, представляющая собой все заголовки HTTP, переданные в запросе HTTP. Результатом остальных запрошенных серверных переменных является число или строка, легко согласуемая с XML, однако ALL_HTTP возвращает все заголовки в одну и ту же серверную переменную.
Заголовки в значении, возвращаемом из ALL_HTTP, ограничены символами новой строки, поэтому требуется дополнительный анализ для размещения каждого заголовка в элементе XML в качестве атрибута. Функция GetALLHTTPHeader выполняет данную задачу с помощью функции ECB GetServerVariable (см. листинг 5.4).
Листинг 5.4. GetALLHTTPHeader Function Building XML Element in SEUX ISAPI Extension (html, txt)
Сравнение ISAPI с сервером ATL
При сравнении ATL Server и ISAPI основным различием является то, что ISAPI в меньшей степени поддерживает инфраструктуру и наличие архитектуры. ISAPI для расширений (в отличие от фильтров) состоит из функций API и структур и классов, являющихся параметрами функций API. ATL Server представляет много новых вспомогательных классов, макросов и функций и выполняет по отношению к ISAPI задачи, аналогичные классам Microsoft Foundation Classes (MFC) применительно к Windows API. ATL Server является дополнительным уровнем программирования, позволяющим оптимально использовать технологии. ATL Server поддерживает разработчика, который создает взаимодействующий с ISAPI программный продукт, предоставляя ему соответствующие методы и вспомогательное программное обеспечение. Разработчик может выбирать используемое ПО (иногда это является сложной задачей). В подобных обстоятельствах ISAPI послужит удобной альтернативой. В отличие от ATL Server ISAPI не предлагает никакой абстракции типа логики, и, кроме этого, имеется не очень много информации об ISAPI. Можно использовать классы ATL Server в приложении ISAPI без применения шаблона проекта ATL Server. В качестве альтернативы шаблон проекта ATL Server настраивается на использование одной библиотеки DLL без каких-либо опций, что создает структуру проекта, похожую на проект ISAPI.
Значения серверных переменных
Возможные значения запрашиваемых серверных переменных приведены в листинге 5.3 в коде функции HttpExtensionProc в расширении ISAPI SEUX; они являются аргументами в вызовах GetECBElement. Значения серверных переменных могут изменяться в процессе текущего события запроса HTTP в IIS, и зачастую переменной не присваивается значение. Серверные переменные содержат значения только при определенных настройках IIS. В таблице 5.2 приведены серверные переменные, запрашиваемые с помощью функции GetServerVariable.
ERROR_INVALID_PARAMETER | Значение hConn является некорректным или закрытым, либо неверны параметры серверной переменной. |
ERROR_INVALID_INDEX | Запрашиваемая серверная переменная не поддерживается. |
ERROR_INSUFFICIENT_BUFFER | Размер lpdwSizeofBuffer слишком мал для содержания значения запрашиваемой серверной переменной. |
ERROR_NO_DATA | Запрашиваемая серверная переменная недоступна. |
ALL_HTTP | Все HTTP-заголовки (разделены символами новой строки), переданные в запросе HTTP в строке с символом конца строки. Заголовки имеют вид <имя заголовка> : <значение>. |
ALL_RAW | Все заголовки HTTP в том виде, в котором они были отправлены запрашивающей HTTP-стороной. |
APPL_MD_PATH | Путь метабазы веб-приложения. Например, /LMW3SVC/1/Root/SimpleISAPI. |
APPL_PHYSICAL_PATH | Физический путь корневого веб-каталога для веб-приложения. Например: C:\ISAPI\. |
AUTH_PASSWORD | Пароль, вводимый веб-пользователем в диалоговом окне аутентификации браузера, если установлена базовая аутентификация. |
AUTH_TYPE | Используемый тип аутентификации. Пустое значение при отсутствии аутентификации либо значение, соответствующее Kerberos, пользовательской аутентификации, SSL/PCT, базовой или интегрированной аутентификации Windows. |
AUTH_USER | Имя пользователя, вводимое пользователем в диалоговом окне аутентификации браузера в случае, если установлена базовая аутентификация. |
CERT_COOKIE | Уникальный идентификатор сертификата клиента. |
CERT_FLAGS | Битовые флаги бюро сертификатов (CA) сертификата клиента. Если bit0 равен 1, то CA отсутствует в списке распознаваемых бюро сертификатов данного сервера и признается недействительным. |
CERT_ISSUER | Содержит имя сертификата клиента. Например, O=Schmidlaps, OU=House, CN= имя пользователя, C=USA. |
CERT_KEYSIZE | Размер ключа в битах при соединении SSL. |
CERT_SERCRETKEYSIZE | Размер секретного ключа сертификата сервера в битах. |
CERT_SERIALNUMBER | Серийный номер сертификата клиента. |
CERT_SERVER_ISSUER | Подробное имя издателя сертификата сервера. |
CERT_SERVER_SUBJECT | Подробное имя субъекта сертификата сервера. |
CERT_SUBJECT | Субъект сертификата клиента. |
CONTENT_LENGTH | Количество байт, исключая заголовки HTTP-запроса. |
LOGON_USER | Если конечный пользователь успешно аутентифицировался в Windows, используется учетная запись входа в систему. |
HTTPS | Возвращает значение off, если в HTTPS не используется SSL, в противном случае возвращается значение on. |
HTTPS_KEYSIZE | Размер ключа SSL-соединения в битах. |
HTTP_SECRETKEYSIZE | Размер секретного ключа сертификата сервера в битах. |
HTTPS_SERVER_ISSUER | Подробное имя издателя сертификата сервера. |
HTTPS_SERVER_SUBJECT | Подробное имя субъекта сертификата сервера. |
INSTANCE_ID | Номер экземпляра сервера. Значения идентификатора сервера в метабазе, например, 1. |
INSTANCE_META_PATH | Путь веб- экземпляра в метабазе, например: LM/W3SVC/1. |
PATH_INFO | Часть URL, расположенная между ISAPI DLL и началом секции с дополнительной информацией в URL. Как правило, в этом месте нет никаких данных, если запрашивающее ПО не добавляет свое значение. |
PATH_TRANSLATED | Часть веб-экземпляра, связанная с физическим жестким диском, с конкатенацией значения PATH_INFO. |
QUERY_STRING | Строка символов, следующих за символом "?" в секции дополнительной информации URL. |
REMOTE_ADDR | IP-адрес хоста или шлюза запрашивающего ПО. |
REMOTE_HOST | Имя узла или шлюза запрашивающего ПО, если включен обратный поиск DNS; иначе возвращается значение IP-адреса узла или шлюза запрашивающего ПО. |
REMOTE_USER | Имя пользователя, осуществляющего HTTP-запрос и аутентифицируемого несущим сервером. Представляет собой пустую строку для анонимного пользователя. |
REQUEST_METHOD | Команда метода HTTP-запроса. |
SCRIPT_NAME | Имя исполняемого двоичного файла, например, имя ISAPI DLL или исполняемого файла CGI. |
SERVER_NAME | Имя узла сервера или IP-адрес. |
SERVER_PORT | Порт TCP/IP, по которому получен запрос. |
SERVER_PORT_SECURE | Значение 0 или 1. Запросы по безопасному порту возвращают 1; иначе возвращается 0. |
SERVER_PROTOCOL | Имя и версия протокола запроса, например, HTTP 1.1. |
SERVER_SOFTWARE | Имя и версия IIS, под которой выполняется программа DLL расширения ISAPI, например, Microsoft-IIS/6.0. |
URL | Значение части url-путь адреса URL, исключая значение PATH_INFO. Например: /simpleisapi/folder1/folder2/SEUX.dll. |
Для демонстрации значений таблицы 5.2 в листинге 5. 5 приведен документ XML, созданный из расширения ISAPI SEUX.DLL. В данном примере несущий сервер и IIS настроены таким образом, что многие значения серверных переменных получаются в процессе HTTP-запроса. Имя несущего узла – amd1700v2. IIS 6 на amd1700v2 настроен с использованием следующих значений параметров и файловых расположений.
Физическое расположение расширения ISAPI SEUX.DLL.
C:\ISAPI\папка1\папка2\SEUX.dll.Корень веб- экземпляра. C:\inetpub\wwwroot.Связанный виртуальный каталог. C:\ISAPI.Анонимный доступ. Не включен для виртуального каталога.Базовая аутентификация. Включена для виртуального каталога.
Расширение ISAPI SEUX.dll запрошено с amd1700v2 с помощью следующих данных браузера, расположенного на отдельном компьютере.
Пользователь, осуществивший вход на веб-сайт под именем normaluser.Пользователь, осуществивший вход на веб-сайт с использованием пароля normaluser.URL в браузере: http://amd1700v2/simpleisapi/folder1/folder2/SEUX.dll/PATH_INFO?parm1=value1&parm2=value
Листинг 5.5. SEUX.DLL Output from http://amd1700v2/simpleisapi/folder1/folder2/SEUX.dll/PATH_INFO? parm1=value1&parm2=value (html, txt)