Модель компонентных объектов (Component Object Model, COM) – это спецификация, разработанная компанией Microsoft для построения программных компонентов, используемых приложениями или программами Windows для расширения своих функциональных возможностей. С помощью COM программное обеспечение, написанное на одном языке (например, на C++), может работать с программой, написанной на другом языке (скажем, на Visual Basic), без перекомпиляции программных компонентов. Это означает, что динамически подключаемую библиотеку, разработанную в C++, можно вызывать из исполняемого файла, написанного на Visual Basic. При работе с активными серверными страницами (ASP) VBScript может вызвать функцию из объекта COM, созданного при помощи языка VB, C++ или любого другого. Веб-разработка с использованием технологии COM осуществляется посредством вызова в ASP функций, расположенных в COM-объектах.
Аббревиатура
Примечание. Термин "потребление" часто используется, когда речь идет о вызове программного обеспечения динамически подключаемой библиотеки (DLL) или другой библиотеки. Этот термин появился в результате изменения терминологии "клиент-сервер", описывающей взаимодействие между клиентом базы данных (программой, осуществляющей запрос или ввод данных) и самой базой. Термины "потребитель" и "провайдер" стали нормой при описании программных компонентов; они отражают процесс взаимодействия между программой, которая базируется на другой программе, и программой, которая обслуживает другую программу.
В отличие от обычного ASP-программирования (см. лекцию 12 курса "Администрирование web-серверов в IIS"), в COM-программировании активные серверные страницы используются в качестве системы организации. ASP упорядочивают HTTP-запросы в команды, осуществляют потребление COM-объектов, непосредственно выполняющих работу, и возвращают ответ клиенту. Преимуществом такого подхода является то, что программа в COM-объекте инкапсулирована в виде единого дискретного элемента, который можно целиком добавить или удалить из системы. Программное обеспечение разрабатывается таким образом, что программисты могут его использовать, но не могут изменять, поскольку к дистрибутиву исходный код не прилагается. В зависимости от языка построения COM-объекта заложенные в программу машинные инструкции могут быть двоичными, выполняемыми с большей производительностью, чем языки сценариев VBScript в ASP.
Архитектура типичного COM-приложения показана на рис. 1.1.
В настоящее время COM-программирование заключается в написании библиотек DLL ActiveX с помощью языка Visual Basic 6 (VB6). Хотя объекты COM можно создавать с помощью других языков, в данной лекции мы будем работать с VB6. Проект VB6 компилируется в обычный исполняемый файл, что полностью избавляет программиста от трудностей, присущих работе с языком описания интерфейса COM (IDL) и управлению архитектурой самого объекта. VB6 является стандартным языком программирования, интегрированная среда разработки (IDE) довольно проста, и поэтому любой пользователь напишет, скомпилирует и запустит программу без особых трудностей.
(рис 1.1) Архитектура веб-приложения COMПримечание. Библиотека ActiveX DLL в VB6 является шаблоном проекта для создания COM-объекта.
После запуска Visual Basic 6 отображается диалоговое окно New Project (Новый проект) (см. рис. 1.2), в котором выбирается тип проекта. Для построения COM-объектов веб-приложения выберите ActiveX DLL и нажмите на кнопку Open (Открыть).
(рис 1.2) Диалоговое окно нового проекта в Visual Basic 6В VB6 можно создать проекты других типов, например, исполняемые файлы и
элементы управления ActiveX. Проекты ActiveX EXE и Standard EXE обычно
используются при разработке приложений. Проект исполняемого файла мы
рассмотрим далее при создании
Из-за ограничений, связанных с разработкой программ в VB runtime, элементы управления ActiveX, написанные на VB, не подходят для веб-разработки, поскольку после установки программы на клиенте зачастую требуется перезагрузка компьютера для работы с новым элементом управления ActiveX.
После выбора типа проекта будет создан новый проект с именем Project1 и
новый класс Class1. Если сразу скомпилировать проект, то конечный файл
будет называться по умолчанию Project1.dll, а идентификатор класса
(CLSID), используемый для идентификации класса в команде ASP Server.CreateObject – Project1.Class1. Имена класса и проекта должны
быть информативными, а не шаблонными именами по умолчанию. Классу
следует присвоить имя применительно к сути создаваемого проекта, а
проекту – имя, определяющее файл хранилища или исполнения, внутри
которого будет находиться класс.
Примечание. Все COM-объекты, созданные с помощью проекта Active X DLL в
VB6, имеют расширение .dll.
Пусть в нашем примере веб-приложение является частью интернет-проекта
по выбору параметров мебели с именем ConfigSeat.
Объект "стул" определен в процессе сбора требований, а создаваемый
класс предназначен для представления этого объекта и является частью
бизнес-логики программного приложения. Данный класс логично назвать clsChair. Префикс cls определяет объект как класс. Элемент Auto List
Members в функции Visual Basic IntelliSense отображает имена частей
проекта и не различает классы и другие типы файлов, например, модули.
Использование префикса cls облегчает идентификацию класса в списке Auto
List Members.
Для изменения имени класса откройте окно свойств с помощью команды
View\Properties Window (Вид\Окно свойств) и выберите класс в Project
Explorer (Диспетчер проектов). Исправьте имя Class1 в области Name
(Имя) на clsChair (см. рис. 1.3). (Остальные параметры в окне свойств
не меняйте, поскольку для этого требуются глубокие знания процесса
разработки VB ActiveX. В данной лекции этот вопрос не рассматривается.)
Вы можете также изменить имя проекта, щелкнув правой кнопкой мыши на имени проекта в Project Explorer (Диспетчер проектов).
(рис 1.3) Окно свойств классаВ диалоговом окне свойств проекта во вкладке General (Общие) имеется
текстовое поле Project Name (Имя проекта), в котором отображается имя
по умолчанию Project1. В нашем примере назовем проект ConfigSeat.
Удалите в текстовом поле имя Project1 и введите ConfigSeat (см. рис.
1.4).
Многие программисты не знают о существовании автоматической нумерации версий в VB6. Номера версий помогают определять последнюю версию разрабатываемой библиотеки DLL с помощью уникальных идентификаторов. При каждой компиляции программного кода номер версии увеличивается. Как правило, объект COM устанавливается на узел несколько раз. Потребители программного обеспечения должны использовать только одну версию (последнюю), и номера версий позволяют работать именно с этой версией. При отсутствии номеров версий для определения последней версии пришлось бы использовать дату создания файла. В некоторых ситуациях (особенно при совместной работе над проектом нескольких программистов) определение номера версии по дате не работает. Для включения автоматического присвоения номеров новым версиям проекта откройте вкладку Make (Создание) в диалоговом окне свойств проекта и отметьте опцию Auto Increment (Автоматическая нумерация). Если вы не сделаете это, ошибки в программе не возникнет. Опция Auto Increment (Автоматическая нумерация) по умолчанию не включена, но мы настоятельно рекомендуем включать ее в каждом проекте.
(рис 1.4) Диалоговое окно свойств проекта с новым именем ConfigSeat
Объект "стул" имеет некоторые атрибуты: цвет, высота, наличие или
отсутствие колес. Эти атрибуты можно присоединить к классу в виде
свойств. Ниже показано, как расширить класс clsChair добавлением
свойства color.
Let и Get.
(рис 1.5) Диалоговое окно Add Procedure (Добавление процедуры)Свойством называется специальная ConfigSeat, а в списке Classes (Классы) в левой части окна содержится
класс clsChair.
(рис 1.6) Браузер объектов отображает класс clsChair и свойство сolor
Выберите класс clsChair, чтобы отобразить добавленное свойство color в
правой области. Выделите свойство color, и в нижней части окна в
области отчета появится детальное описание этого свойства с указанием
типа, класса и библиотеки, которым оно принадлежит.
Свойство color в его текущем состоянии является практически
бесполезным, так как для его значений еще не определены переменные. Без
этих переменных установка значения свойства не позволит ни сохранить
значение, ни получить его. Свойство используется для изменения значения
в классе, которое находится в памяти при работе класса, поэтому нужно
объявить локальную переменную с областью действия, охватывающей весь
класс.
Значение color представляет собой строку, описывающую цвет стула,
поэтому в верхней части кода класса объявим частную (private) строковую
переменную с именем m_scolor. Ключевое слово private означает, что
переменная недоступна программе за пределами класса. Область действия private целесообразно использовать при контроле доступа потребителей к
членам класса, свойствам, подпрограммам и функциям. При работе возможна
ситуация, когда потребуется изменить другие значения класса или
проверить цвет при его установке. Если локальная переменная m_scolor
будет общей, то потребитель класса сможет изменить ее значение, не
поставив в известность класс.
Рекомендуется всегда использовать свойства для разрешения установки или считывания атрибута в классе. Данный подход несколько затрудняет программирование и повышает уровень сложности программного решения, однако в будущем будет проще вносить изменения в класс. Если правила работы класса поменяются, то обновление объекта COM гораздо легче реализовать под общим интерфейсом COM, поскольку код, лежащий в основе функций свойства, используется для корректировки атрибута класса без изменения общего интерфейса класса. Изменение интерфейса класса потребует изменения потребителей класса, поэтому сложности из-за отсутствия абстракции между внутренними членами класса и его внешним интерфейсом, окажутся более серьезными по сравнению с первоначальным усложнением проекта.
В листинге 1.1 приведен код, реализующий класс clsChair.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' constants to class Private Const DEFAULT_COLOR = "Brown" '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' locals to class 'holds the color of the chair Private m_scolor As String '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public Property Get color() As Variant color = m_scolor End Property Public Property Let color(ByVal vNewValue As Variant) m_scolor = vNewValue End Property Private Sub Class_Initialize() 'set default color on instantiation m_scolor = DEFAULT_COLOR End Sub
Вверху каждого файла кода в VB рекомендуется размещать выражение Option
Explicit. Оно проверяет все необъявленные переменные, используемые в
коде, при компиляции. При обнаружении таких переменных VB прерывает
компиляцию и генерирует сообщение об ошибке. Данное выражение позволяет
принудительно объявлять переменные, что полезно для выявления опечаток
в именах переменных. Можно провести долгие часы, пытаясь понять, почему
переменная не содержит нужного значения, и в результате обнаружить, что
эта переменная просто неправильно указана в строке кода. Выявить такие
ошибки трудно, поэтому используйте команду Option Explicit. VB
настраивается на автоматическое добавление данного выражения в код
каждого файла с помощью команды Tools\Options (Сервис\Параметры).
Откройте вкладку Editor (Редактор) и отметьте опцию Require Variable
Declaration (Требовать объявление переменных).
Любое программное обеспечение необходимо тестировать, и VB IDE для этого имеется прекрасный механизм. Нажмите на кнопку Start (Пуск) в панели инструментов VB либо на клавишу F5, чтобы откомпилировать и выполнить программу.
Поскольку проект ConfigSeat является библиотекой ActiveX DLL, его
нельзя выполнить, т.к. он должен использоваться другой исполняемой
программой. Для тестирования класса clsChair следует создать еще один
проект в том экземпляре IDE, где редактируется clsChair.Это будет
исполняемая программа с одной задачей – тестированием класса clsChair.
Программа для тестирования другой программы называется тестовой
структурой.
Project1, содержащий форму Form1.clsChairTester.clsChair недоступен, поскольку в тестовой
структуре clsChairTester нет ссылки на проект ConfigSeat. Для создания
ссылки выберите команду Project\References (Проект\Ссылки) для открытия
диалогового окна References (Ссылки) (см. рис 1.7(рис 1.7) Диалоговое окно проекта References (Ссылки)ConfigSeat, отметив соответствующую ей
опцию, после чего нажмите на кнопку OK.Запомните. В диалоговом окне References (Ссылки) отображаются ссылки для выбранного в настоящий момент проекта. Изменение ссылок применяется только к этому проекту. Вы можете случайно выделить и другие проекты в группе проектирования, поэтому перед внесением изменений убедитесь в том, что выбрано соответствующее диалоговое окно References (Ссылки) с именем окна активного проекта в строке заголовка.
Элемент form1 можно настроить на отображение функционирования различных
компонентов класса clsChair. Используемый подход заключается в
представлении всех свойств класса в виде текстовых полей, всех функций
– в виде кнопок, с текстовыми полями для аргументов формы тестовой
структуры соответствующего класса. Тестовую структура нужно сохранить
вместе с исходным кодом тестируемого класса, так как в будущем это
поможет при усовершенствовании класса или устранении ошибок.
Примечание. Рассматриваемая тестовая структура – clsChairTester –
сохранена с исходным кодом данной лекцию и доступна на веб-сайте автора
книги.
В классе clsChair имеется только одно свойство, поэтому тестовая
структура просто установит значение свойства и покажет его
пользователю. После добавления в форму нескольких текстовых полей и
командной кнопки, написания кода для создания и управления классом clsChair можно протестировать компонент "стул" с помощью тестовой
структуры.
Brown (Коричневый).На рисунке 1.8 показана тестовая структура, при работе которой цвет стула успешно изменен в нескольких тестах.
(рис 1.8) Тестовая структура clsChair тестирует свойство color
Теперь, когда класс clsChair прошел модульное тестирование в тестовой
структуре, он почти готов для использования в веб-приложении. Однако
перед этим его нужно скомпилировать и разместить на несущем сервере.
Выполните следующие действия.
ConfigSeat.ConfigSeat.dll (Файл\Создать ConfigSeat.dll ).Откроется диалоговое окно Make Project (Создать проект), в котором нужно ввести имя файла и расположение новой библиотеки DLL. Измените имя файла или путь к файлу, если это необходимо, и нажмите на клавишу OK.
VB откомпилирует проект ConfigSeat и создаст файл .dll. Библиотека DLL
автоматически зарегистрируется на узле, и ее можно будет сразу
использовать. (О регистрации DLL речь пойдет в следующем подразделе.)
После копирования библиотеки ConfigSeat.dll на сервер ее необходимо
зарегистрировать или загрузить в службы компонентов как приложение
COM+. Для регистрации компонента компания Microsoft разработала утилиту
командной строки regsvr32.exe. Для работы с ней выполните следующие
действия.
<имя COM DLL> – имя файла
библиотеки COM DLL). Для файла библиотеки ConfigSeat.dll команда имеет
вид regsvr32 ConfigSeat.dll, а курсор командной строки при выполнении
команды должен находиться в той же папке, что и файл ConfigSeat.dll.
При запуске regsvr32 из другого места расположения в команде следует
указать полный путь к файлу .dll на сервере. Например, если файл ConfigSeat.dll расположен в папке C:\bin\, то команда имеет вид regsvr32 C:\bin\ConfigSeat.dll.Для удаления библиотеки DLL COM или замены ее другой библиотекой
следует аннулировать регистрацию библиотеки DLL и удалить
соответствующий файл. При аннулировании регистрации из реестра
удаляется запись CLSID для данной библиотеки, чем достигается "чистота"
реестра и сокращается количество записей. Выполните те же самые шаги, с
помощью которых проводилась регистрация, но используйте в команде ключ /u. Например, для аннулирования регистрации файла C:\bin\ConfigSeat.dll
команда примет вид regsvr32 /u C:\bin\ConfigSeat.dll. Для просмотра
При работе с regsvr32 не возникает каких-либо проблем. Это идеальное программное решение, не требующее управления и дополнительной информации о COM-объекте. Регистрация COM-объектов с помощью regsvr32 прекрасно подходит для приложения рабочего стола.
Установка объекта COM в службах компонентов более предпочтительна для веб-приложений по сравнению с использованием regsvr32, поскольку компоненты веб-приложении зачастую требуют последующего управления и обновления компонентов. Любое программное обеспечение, загруженное в службы компонентов, называется компонентом. Службы компонентов имеют больше возможностей по управлению компонентами, например:
Для загрузки объекта COM в службы компонентов сначала нужно создать приложение COM+. Приложение COM+ содержит один или более объектов или компонентов COM. Приложение COM+ в службах компонентов интерпретируется как идеальный (с точки зрения потребителя) развертываемый модуль. Приложение COM+ может использоваться другим процессом, или процесс, под которым выполняется приложение COM+, может быть предоставлен службам компонентов. Запуск (или остановка) приложения COM+ включает (или запрещает) использование всех его компонентов. Если наряду с надежными компонентами загружены ненадежные, то надежные компоненты нужно переместить в другое приложение COM+, которое не требует такого количества административных изменений, как приложение COM+ с проблемными библиотеками DLL. Такая стратегия минимизирует время простоя компонентов приложения, которое не будет "списано со счета" из-за ошибки в одном-единственном компоненте. Появляется возможность более четкого управления установкой компонента, изолированного от остальных надежных компонентов, пока его надежность не будет доказана.
Ниже приведены шаги, с помощью которых новое приложение добавляется в службы компонентов.
Примечание. С помощью консоли MMC
В первом окне мастера нажмите на кнопку Next (Далее).
(рис 1.9) Добавление нового приложения в консоль управления Components Services (Службы компонентов).В окне Install Or Create A New Application (Установка или создание нового приложения) (см. рис. 1.10) нажмите на кнопку Create An Empty Application (Создать пустое приложение) для перехода к следующему окну.
(рис 1.10) Окно Install Or Create A New Application (Установка или создание нового приложения) мастера установки приложения COM+В окне Create Empty Application (Создать пустое приложение) (см. рис.
1.11) введите имя приложения COM+; в нашем случае – New ConfigSeatWeb.
Имя приложения COM+ не играет особой роли с точки зрения
программирования, оно определяет приложение COM+ в консоли управления
службами компонентов. Библиотека DLL ConfigSeat является новым
компонентом, поэтому выберите значение по умолчанию
(рис 1.11) Окно Create Empty Application (Создание пустого приложения) мастера установки приложения COM+В окне Set Application Identity (Установка принадлежности приложения)
(см. рис. 1.12) параметром по умолчанию является Interactive User
(Интерактивный пользователь). Здесь можно указать одну из встроенных
учетных записей: Local Service (Локальная служба) или
(рис 1.12) Окно Set Application Identity (Установка принадлежности приложения) мастера установки приложения COM+Не используйте этот параметр при работе с несущими компонентами приложения COM+, так как приложение COM+ не будет запускаться после выхода пользователя из системы узла.
Учетная запись
(рис 1.13) Окно Add Application Roles (Добавление ролей приложения) мастера установки приложения COM+Роли создаются из соответствующих учетных записей пользователей Windows. Нажмите на кнопку Add Role для добавления дополнительных ролей в приложение COM+. В данном случае добавлена роль по умолчанию с именем CreatorOwner. Эта роль прекрасно подходит для приложения COM+ в нашем примере. Для продолжения работы нажмите на кнопку Next (Далее).
В окне Add Users To Roles (Добавить пользователей в роли) (см. рис. 1.14) в роли, определенные в окне добавления ролей приложений, можно добавить учетные записи пользователей Windows. По умолчанию ваша учетная запись Windows будет использоваться в каждой роли, определенной в предыдущем окне. Учетные записи Windows, добавленные в роли, предназначены для предоставления аутентификационных данных, под которыми выполняются процессы. Учетная запись Windows webuser – единственная запись, добавленная в роль CreatorOwner (см. рис. 1.14). Нажмите на кнопку Next (Далее) для продолжения работы.
(рис 1.14) Окно Add Users To Roles (Добавление пользователей в роли) мастера установки приложения COM+ с учетной записью, добавленной в роль CreatorOwner.Для понимания различий между серверным приложением и приложением библиотеки в службах компонентов необходимо знать некоторые термины и механизмы архитектуры Windows. Процессом называется исполняемая программа, которая выполняется в данный момент. Операционная система Windows предоставляет процессорное время для каждого порожденного процесса. Нитью называется работа, выполняемая внутри процесса. Процесс может поддерживать одновременно несколько нитей. Если нити в процессе отсутствуют, то процесс считается выполненным, и Windows не выделяет ему процессорное время.
Чем больше процессов выполняется, тем больше ресурсов используется компьютером для обеспечения их работы. Запуск процесса изначально требует значительного количества ресурсов сервера. Остановка одного процесса не влияет на другие процессы, если последние не нуждаются в нем. Остановка процессов является лояльным действием, не представляющим риск для стабильности системы, поэтому распределение большего количества работы между процессами требует большего объема системных ресурсов, но обеспечивает более высокий уровень надежности.
Стремясь к сокращению системных ресурсов, связанных с запуском и работой процессов, программисты разрабатывают программное обеспечение для загрузки в память под существующим процессом вместо создания нового процесса. Сравнение веб-приложений Common Gateway Interface (CGI) и веб-приложений ASP показывает различие, о котором идет речь. Если на веб-странице, требующей работы приложения CGI, наблюдается 10 посещений в минуту, то независимо от сложности этой работы серверу придется запускать исполняемый файл CGI 10 раз в минуту, т.е. 600 раз в час.
Если страница ASP выполняет те же задачи, что и исполняемый файл CGI, то через один и тот же интервал времени запускаются нулевые процессы. На самом деле запускается лишь один процесс, и это происходит при старте сервера; этот процесс – IIS. Расширение ISAPI ASP.DLL работает в пространстве процесса IIS. Раньше службы IIS останавливались без видимых причин после продолжительного периода времени. Подобные ошибки возникали из-за повреждения процесса IIS и его дестабилизации исключением, утечкой памяти или невыпущенными указателями. Причиной этому была загрузка библиотеки DLL с дефектами в пространство процесса IIS. Эта унаследованная особенность (или ошибка) в архитектуре Windows привела к тому, что IIS воспринимается как ненадежная система в сравнении с другими, менее сложными системами, использующими CGI.
Для повышения надежности без потерь производительности (что возможно
при работе программного обеспечения в собственном независимом процессе)
был разработан сервер Microsoft Transaction Server (
Цель создания приложения COM+ – дать возможность службам компонентов
обслуживать экземпляры классов в ConfigSeat.dll. Следующим шагом по
установке ConfigSeat.dll на несущем сервере является добавление
ConfigSeat.dll в только что созданное приложение COM+ New
ConfigSeatWeb.
В консоли управления Component Services (Службы компонентов) щелкните правой кнопкой мыши на папке Component (Компонент) под пунктом приложения COM+ New ConfigSeatWeb и выберите команду New\Component (Создать\Компонент) (см. рис. 1.15).
(рис 1.15) Запуск мастера установки компонентов COM+ConfigSeat.dll и нажмите на
кнопку Open (Открыть).В окне Install New Components (Установка новых компонентов) приведен список компонентов, добавляемых в новое приложение COM+ (см. рис. 1.16 ).
(рис 1.16) Окно Install New Component (Установка нового компонента)
мастера компонентов COM+ с результатом загрузки библиотеки ConfigSeat.dll.
Данное окно предназначено для открытия библиотек COM DLL, загрузки их в приложение COM+ и отображения выбранных элементов. Нажмите на кнопку Add (Добавить) для открытия диалогового окна выбора файла (см. шаг 4). Выбор других библиотек COM DLL добавит их в списки файлов и компонентов, отображаемые в этом окне. Нажмите на кнопку Next (Далее).
ConfigSeat.dll будет добавлена в
приложение COM+ New ConfigSeatWeb.Службы компонентов разрешают ролевой доступ к любому компоненту, загруженному в приложение COM+. Учетные записи пользователей Windows приписываются к роли, и запросы компонента выполняются с помощью аутентификационных данных этих учетных записей. Если эти роли связаны с запрашиваемой частью компонента, то программа-потребитель будет функционировать должным образом; в противном случае она не сможет осуществить доступ к компоненту. Роли связываются с компонентом, загруженным в приложение COM+, на следующих уровнях:
Следует включать ролевой доступ, начиная с верхнего уровня и далее вниз, до нужного уровня контроля доступа. В качестве метода компонента можно определить низшую дискретную функциональность, реализующую контроль доступа. Для включения ролевого доступа выполните следующие шаги.
Чтобы включить проверку доступа уровня компонента для приложения COM+, выполните следующие шаги.
Для включения проверки доступа для компонента нужно включить проверку доступа для приложения COM+ и после этого выполнить следующие шаги.
Для присвоения роли компоненту в целом отметьте роль в списке Roles Explicitly Set For Selected Item(s) (Роли, установленные для выделенных элементов). Все методы компонента унаследуют данную роль.
Для присвоения роли определенным методам внутри компонента отметьте опцию Enforce Component-Level Access Checks (Обязательная проверка доступа на уровне компонента), что позволит в дальнейшем присваивать роли методам компонента.
Для компонента ConfigSeat.clsChair, добавленного в приложение COM+ New
ConfigSeatWeb, ролевой доступ не требуется, поэтому обязательные
проверки доступа уровня компонента не включены. Приложение COM+ New
ConfigSeatWeb, тем не менее, настроено на обязательную проверку
доступа, поэтому проверки доступа компонентного уровня включены. Если
система IIS функционировала под учетной записью по умолчанию, созданной
Windows (например, IUSR_имя_компьютера ), то ASP-программа, создающая
объект ConfigSeat.clsChair, вызовет ошибку, поскольку гостевая учетная
запись интернета не имеет доступа к компоненту ConfigSeat.clsChair.
После смены ее на другую учетную запись с доступом к указанному
компоненту код ASP будет функционировать должным образом. Для
использования кодом ASP компонента ConfigSeat.clsChair веб-сайт или
виртуальный каталог в IIS настроен на работу с использованием
аутентификационных данных учетной записи webuser.
Для настройки доступа выполните следующие шаги.
Теперь страницы ASP будут выполняться под учетной записью webuser. При
создании страницами ASP компонента ConfigSeat.clsChair
аутентификационные данные учетной записи webuser представляются для
запроса в службы компонентов. Службы компонентов проверяют разрешения
учетной записи webuser на создание и использование компонента, и ASP
реализует функции в компоненте ConfigSeat.clsChair.
Для тестирования библиотеки ConfigSeat.dll можно создать несложный код
ASP, реализующий экземпляр класса clsChair для вывода значения color в
браузер и изменения этого значения. Файл ASP DescribeChair.asp (см.
листинг 1.2) можно расположить в веб-приложении на сервере с
библиотекой ConfigSeat.dll. Файл ASP можно расположить на веб-сайте по
умолчанию, созданном при установке IIS. Если сервер не настроен на
выполнение exe-файлов, то проведите соответствующую настройку. Для
получения инструкций по реализации работы ASP в IIS6 обратитесь к лекции 12 курса "Администрирование web-серверов в IIS".
<%@ Language=VBScript %>
<HTML>
<HEAD>
</HEAD>
<BODY>
<%
dim o
Response.Write("<p>start Test</p>")
'create the object since this is hard work
set o = Server.CreateObject("ConfigSeat.clsChair")
'demonstrate that values were changing
Response.Write("<p> color=" o.color "</p>")
Response.Write("<p>change color to blue</p>")
o.color = "blue"
Response.Write("<p> color=" o.color "</p>")
'destroy object so it can be created again
set o = nothing
%>
</BODY>
</HTML>
Для демонстрации возможностей служб компонентов DescribeChair.asp
следует запустить много раз. Нагрузка на веб-сервер, созданная
запросами на файл ASP, не обеспечивает достаточный спрос на компонент
COM или сервер, на котором он расположен, поэтому службы компонентов не
зарегистрируют потребность в ресурсах. Microsoft предлагает две
утилиты, предназначенные для проведения проверки нагрузкой.
WAS – бесплатная программа; Microsoft Application Center Test входит в пакет Visual Studio .NET Enterprise Edition.
Для создания нехватки ресурсов в ASP и просмотра реакции на это условие
в Microsoft Application Center Test был создан простой сценарий,
моделирующий одновременную работу ста пользователей в течение 5 минут.
Такая нагрузка достаточно велика, и службы компонентов испытывали
большую нагрузку при обслуживании экземпляра clsChair. В каждый момент
времени создавалось от нуля до пяти экземпляров clsChair,
обеспечивавших 175 запросов на страницы в секунду. На рисунке 1.17
показана консоль управления службами компонентов, отображающая
состояние класса clsChair при тестировании нагрузкой.
(рис 1.17) Консоль управления службами компонентов, отражающая
использование класса clsChair
До сих пор мы показывали построение простейшего веб-приложения COM,
включая все этапы процесс разработки. В реальном COM-объекте должен
присутствовать набор классов, отражающий объекты, выявленные в процессе
сбора требований. Среди возможностей веб-приложений COM следует
отметить хранение данных, связанных с выявленными объектами, чтение
данных об этих объектах,
Объектно-ориентированное (ОО) проектирование и анализ представляют собой большую редкость в современном сообществе разработчиков программного обеспечения. Веб-программы не менее сложны, чем другое комплексное программное обеспечение, имеют неопределенную структуру при разработке и дизайне, поэтому не следует игнорировать зарекомендовавшие себя правила и подходы к разработке.
В организациях проектирование и анализ зачастую выполняются после создания продукта, и в этом случае каждое усовершенствование требует его перестройки. В любом проекте время, отведенное для анализа и проектирования, влияет на завершение процесса программирования в намеченные сроки, позволяет в будущем без особых проблем усовершенствовать программу и усиливает командный дух специалистов, занятых разработкой.
Существует проблема, связанная с ОО-анализом и проектированием в VB6. VB6 не позволяет создать действительно объектно-ориентированное программное решение. Эта среда программирования не поддерживает наследование реализации. Отсутствие реального полиморфизма и других возможностей ограничивает его эффективность при разработке приложений, обеспечивающих долговечность, особенно для масштабируемого программного решения. Объекты COM можно построить на других ОО-языках, например, на C++ и Java.
VB6 поддерживает другие возможности истинно полиморфного языка, но
наследование классов – очень важная функция – в нем отсутствует. Не
следует воспринимать наследование в VB6 за истинное наследование.
Документация Microsoft описывает VB6 как объектно-ориентированный язык,
обеспечивающий наследование классов с помощью команды implements.
Однако команда implements обеспечивает только наследование интерфейса.
С практической точки зрения это означает, что IDE в VB6 заново
конструирует интерфейс суперкласса в
VB6 позволяет быстро разработать надежные компоненты, обеспечивающие функциональность, связанную с экземпляром класса. Классы используют другие классы, что весьма полезно. Вероятно, лучшей демонстрацией возможностей VB6 является проект, в котором на этапе сбора требований выявлено немного объектов, или проект с небольшим потенциалом для масштабируемости в будущем и с коротким циклом разработки. VB6 является альтернативой истинно полиморфного языка типа C++, требующего от программиста высокого уровня знаний, и технологии сценариев типа VBScript ASP.
Возьмем созданный ранее объект "стул" и используем его в дальнейшем
процессе разработки, т.е. усовершенствуем объект, добавив функции
чтения и записи данных в базу данных, упорядочивание состояния
экземпляра класса и его фиксирование в документе XML. В класс clsChair
добавятся следующие функции.
OpenChair(ID as string) as Boolean – открывает имеющуюся запись "стул"
и заполняет объект значениями.CreateChair() as Boolean – генерирует новый ID, заполняет объект новым
ID и записывает запись в базу данных.GetChairState() as XMLDOM – упорядочивает состояние объекта в XML DOM в
виде: <Chair ID="" Color="" />.В класс clsChair добавятся следующие свойства.
ChairID as String – Read Only. Идентификатор, используемый для
уникальной идентификации рассматриваемого объекта "стул".ChairError as String – Read Only. Описание последней обнаруженной
ошибки, имевшей место в классе clsChair.Интерфейс по-прежнему не сложен, однако теперь он более соответствует
классу в истинном объектно-ориентированном программном решении.
Целесообразно добавить в интерфейс и другие функции: delete (удаление)
и save (сохранение) – однако для сокращения приводимых в книге примеров
рассматривать их не будем.
Имя chair предшествует именам функций в классе clsChair. Создавать
интерфейс к объекту, использующий имя самого объекта, не рекомендуется,
однако этого требуют ограничения данной технологии. Оpen и create
являются ключевыми словами, зарезервированными в VB, поэтому их нельзя
использовать в качестве имен пользовательских функций в экземпляре
класса. Следует заметить, что наследование класса не содержит
какой-либо логики, за исключением того, что связано с описанием самого
стула или с его действиями в рассматриваемом сценарии. Отсутствует
логика данных или логика представления, например, строки подключения к
базе данных или HTML-вывод.
В листинге 1.3 приведен общий интерфейс объекта "стул"; он содержит объявления следующих функций, включая код реализации.
clsChair Prototypes Public Property Get color() As Variant End Property Public Property Let color(ByVal vNewValue As Variant) End Property Public Property Get ChairError() As String End Property Public Property Get ChairID() As String End Property Public Function OpenChair(ID As String) As Boolean End Function Public Function CreateChair() As Boolean End Function Public Function GetChairState() As DOMDocument30 End Function
Свойства в VB представляют собой обычные функции для упрощения доступа
и присвоения значений. Программист может включить в подпрограмму
свойства код, реализующий работу программы. Рекомендуется создавать
функции или подпрограммы для ситуаций, в которых работа выполняется
программой. Хорошим примером функции в классе clsChair, являющейся
свойством "только для чтения", будет GetChairState(). GetChairState()
выполняет работу по созданию кода XML, поэтому она размещена в функции,
возвращающей экземпляр класса. Если класс DOMDocument30 сохранен в
локальной переменной класса и инициирован после вызова функции Open()
или Create(), то использование свойства с доступом "только для чтения"
является лучшим способом возврата экземпляра класса DOMDocument30.
Поскольку свойства ChairError и ChairID доступны только для чтения, то
при попытке записи в функцию значения произойдет ошибка. Свойство color
является единственным свойством, поддерживающим чтение и запись,
поскольку существуют два прототипа свойства – Get и Let. Свойства ChairError и ChairID доступны только для чтения, поэтому содержат
только прототип Get.
Ни в одном фрагменте кода данной лекции не показана еще одна возможность
VB, которая, правда, не очень важна. Свойство может принимать и
возвращать аргумент экземпляра класса. Если для принятия экземпляра
класса используется прототип свойства, то используется ключевое слово Set, а не Let. Например, если класс clsChair имеет свойство записи ChairState, которое воспринимает экземпляр класса XML DOM как аргумент,
то прототип выглядит следующим образом:
Public Property Set ChairState(ByVal vNewValue As DOMDocument30) End Property
Общей проблемой VB-приложений является неправильная поддержка
абстракции логики. Если класс clsChair создан для чтения и записи
данных в источник типа базы данных, то программист может включить в
этот класс свойство Connection. Свойство Connection предоставляет
классу информацию, необходимую для подключения к базе данных. Такой
подход нежелателен, потому что возникают проблемы с расширяемостью
интернет-приложений, написанных на языке VB. Интерфейс класса не
отражает реальное положение дел, поскольку объект "стул" не имеет
атрибута Connection на самом деле. Размещая свойство Connection в
интерфейсе, программист предполагает, что потребителю класса известно,
каким образом класс взаимодействует с источником данных. Атрибут Connection и подобные технические атрибуты не должны вредить
интерфейсу. Здесь правильным решением является абстрагирование в
бизнес-логике от всего, что не относится к объекту в реальной жизни.
Как программист может обеспечить "чистоту" логической абстракции класса и реализовать подключение к базе данных? Ввод вручную информации о подключении в классе, разумеется, не выход из положения, так как требует изменения кода. Всякое программное обеспечение должно иметь параметры состояния, доступные при инициализации или конструировании. Для сервера Windows механизмом хранения данных состояния или инициализации является реестр, который используется всеми утилитами и службами поддержки Windows. Технология .NET унаследовала использование файлов XML для хранения данных о развертывании и состоянии интернет-приложений.
Любая система работает до тех пор, пока программному обеспечению
известен контекст хранения данных инициализации. Реестр Windows
отыскивается всегда одинаково, независимо от узла его расположения.
Программа не должна искать реестр на диске C:, ведь на другом сервере
он может располагаться в другом месте. Реестр обладает контекстом,
связанным с самим узлом, а не с положением файла на узле, внутри
сервера или внутри сервера на отдельном узле. В интернет-приложениях
корневой веб-каталог выступает в роли общего узла контекста. К
содержимому или файлам можно обращаться в контексте корневого
веб-каталога. Он может располагаться на диске C: или D:, и при
выражении контекста как корневого веб-каталога не возникнет проблем,
связанных с нахождением значения данного параметра инициализации.
Платформа .NET унаследовала стандарт хранения данных развертывания в
файлах XML с именем Web.config, которые располагаются в любом каталоге
структуры веб-каталогов. Более подробная информация о приложениях .NET
и использовании файла web.config приведена в лекциях 2 и 3.
Так как класс clsChair размещен в приложении COM+, то реализован
интерфейс IobjectConstruct для получения аутентификационных данных при
подключении к базе данных. Для его использования в список ссылок
проекта класса добавлена ссылка COM+
Интерфейс IObjectConstrucion реализован с использованием команды Implements, и в класс добавлена подпрограмма события IObjectConstruct_Construct. Эта подпрограмма выполняется при
инициализации класса и передает экземпляр объекта классу,
представляемому параметром pCtorObj. Экземпляр класса, на который
указывает pCtorObj, имеет свойство ConstructString. Значение ConstructString использовалось для инициализации объекта ADO Connection, повсеместно применяемого в классе clsChair. В листинге 1.4
показана подпрограмма события IObjectConstruct_Construct.
IObjectConstruct_Construct event subroutine implementation in clsClass
Option Explicit
Implements IObjectConstruct
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' ***** constants to class *****
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'old style connection string in case nothing else works
Private Const DEFAULT_CONSTRUCTION_STRING = _
"driver={Microsoft Access Driver (*.mdb)};" _
"dbq=D:\aspData\employees.mdb"
Private Const DEFAULT_COLOR = "Brown"
Private Const CHAIR_ID = "ID"
Private Const CHAIR_COLOR = "Color"
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' ***** locals to class *****
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'holds the color of the chair
Private m_scolor As String
'Chair ID for class instance
Private m_sID As String
'holds the ADO Connection to the data
'source that the object interacts with
Private m_Connection As ADODB.Connection
Private m_sErrorMessage As String
Private Sub IObjectConstruct_Construct(ByVal pCtorObj As Object)
On Error GoTo Sub_Error_Handler
Const ERROR_MESSAGE_INFO = "IObjectConstruct_Construct"
Dim sConnection As String
sConnection = pCtorObj.ConstructString
'make certain there is something
If Len(sConnection) < 1 Then
sConnection = DEFAULT_CONSTRUCTION_STRING
End If
'establish connection to database server
If m_Connection Is Nothing Then
Set m_Connection = CreateObject("ADODB.Connection")
End If
m_Connection.Open sConnection 'DEFAULT_CONSTRUCTION_STRING
'establish connection to database server
Set m_Connection = CreateObject("ADODB.Connection")
m_Connection.Open sConnection '"DSN=ASPExample"
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub_Exit_Done:
Exit Sub
Sub_Error_Handler:
'record the error in class instance and rethrow
'for consuming software to learn of issue
ProcessErr ERROR_MESSAGE_INFO _
" Failure obtaining database connection information." _
" Class will not connect to database"
End Sub
Значение свойства ConstructString устанавливается в окне свойств службы
компонентов. Для clsClass строка подключения задана в текстовом поле
Constructor String (Строка конструктора) вкладки Activation (Активация)
окна свойств компонента ConfigSeat.clsClass (см. рис. 1.18). При
использовании данного механизма хранения данных о состоянии
инициализации класс clsChair настраивается при помощи обычных служб
Windows Server, с которыми знаком любой инженер, обслуживающий такой
сервер.
Примечание. Технология доступа к данным Windows, использующая
m_Connection, является локальным по отношению к классу clsChair (см.
рис. 1.4). Это означает, что подключение открыто, пока существует
экземпляр класса clsChair. При уничтожении экземпляра класса clsChair
экземпляр подключения ADO уничтожается, однако провайдер ODBC или
OLE-DB сохраняет экземпляр подключения для следующего запроса. Не нужно
кэшировать объекты подключения или создавать ситуации, требующие
кэширования, поскольку Windows и так выполняет эту функцию.
(рис 1.18) Вкладка Activation (Активация) окна свойств ConfigSeat.clsClass
Взаимодействие с базой данных выводит нас на новый уровень сложности приложения, для которого требуется большая надежность в критических ситуациях. Корректная поддержка ошибок является необходимым условием реализации любого кода; она должна обрабатывать ситуации, которые вызывают возникновение ошибки в подпрограмме, например, при взаимодействии с пользователем или при соединении с разнородными системами.
В Visual Basic имеется система обработки ошибок, легкая в использовании и управлении. Отсутствие обработки ошибок распространяется и на программу-потребителя. В этом случае пользователь видит малоинформативное сообщение, и программа прерывает свою работу. В веб-приложении, где COM-объект используется страницей ASP, конечному пользователю отображается сообщение об ошибке, если IIS настроен на показ таких сообщений.
Каждая исключительная ситуация, имеющая место в классе clsChair,
фиксируется в журнале событий и сохраняется в локальной переменной
свойства ChairError. Код написан таким образом, что при получении
информации об ошибке приостанавливается его работа. Обработка ошибок в
классе clsChair реализована с использованием той же sub_Exit_Done и sub_Error_Handler. Строка sub_Error_Handler
представляет стратегию, согласно которой действия осуществляются при
возникновении исключительных условий, указанных в выражении On Error.
Код, следующий за строкой sub_Exit_Done, представляет собой обычную
стратегию выхода функции или подпрограммы, если при работе программы не
возникают исключительные ситуации. В листинге 1.5 приведена типовая
структура системы обработки ошибок, примененная в классе clsClass.
Error Handling Framework On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "This Function's name" Part of the function that actually does something here '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done: 'return success value On Error Resume Next 'destroy objects Exit Function Sub_Error_Handler: ProcessErr "message about the failure in terms of function"
Подпрограмма ProcessErr, вызываемая в рамках стратегии обработки
исключительных условий, обрабатывает ошибки VB или другие неверные
условия. ProcessErr выполняет следующие действия:
Журнала не будет заполняться до тех пор, пока компонент не будет скомпилирован, по причине ограничения VB и мер безопасности Windows. При выполнении компонента в VB IDE журналы событий не ведутся.
В листинге 1.6 приведен код подпрограммы ProcessErr.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'ProcessErr 'formats error and stores it in error local 'then write to event log. Event logging 'will not function in IDE - only in compiled. ' 'in: vsMessage - usually denoting function 'out: nothing '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Private Sub ProcessErr(ByVal vsMessage As String) Const ERROR_SEPARATOR = " -- " Const NOW_TIME_FORMAT = "yyyy mmm d hh:mm:ss" Const A_SPACE = " " Const ERROR_NUM = " Error #" Const ERROR_BY = " was generated by " Dim sDateTime As String 'get a time data stamp sDateTime = CStr(Format(Now, NOW_TIME_FORMAT)) _ ERROR_SEPARATOR 'construct the error entry vsMessage = sDateTime vsMessage 'add err object data to the error entry m_sErrorMessage = vsMessage ERROR_NUM Err.Number _ ERROR_BY Err.Source A_SPACE Err.Description vbCrLf 'write to event log App.LogEvent m_sErrorMessage, vbLogEventTypeError End Sub
ProcessErr записывает время и добавляет его к описанию ошибки. Свойства
класса VB Err конкатенируются в строку, которая станет частью сообщения
об ошибке, фиксируемого и сохраняемого в локальной переменной ошибки.
Реализация функций CreateChair и OpenChair требует взаимодействия с
базой данных. Функция CreateDir вставляет данные о новом объекте "стул"
в базу данных, в OpenChair заполняет состояние экземпляра класса
значениями, считанными из базы данных. Функция Createchair генерирует
для этого объекта идентификатор ID, создает команду SQL и записывает
новые значения в базу данных при помощи выражения SQL INSERT. В
листинге 1.7 приведен код функции CreateChair.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'CreateChair
'Generates a new ID, populates object with
'the new ID, writes record to DB
'
'in: nothing
'out: returns true on success and false otherwise
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Function CreateChair() As Boolean
On Error GoTo Sub_Error_Handler
Const ERROR_MESSAGE_INFO = "CreateChair"
Const COMMAND_PREFIX = "INSERT INTO tblChair" _
" ([ID], [Color]) VALUES ('"
Const COMMAND_CONJUNCTION = "', '"
Const COMMAND_SUFFIX = "')"
Dim sNewID As String
Dim sSQL As String
'get new ID
sNewID = CreateNewID
'build the insert statement
sSQL = COMMAND_PREFIX sNewID _
COMMAND_CONJUNCTION m_scolor COMMAND_SUFFIX
'perform database update
If Not ExecuteCommand(sSQL) Then
Err.Raise 1001, ERROR_MESSAGE_INFO, _
"Failure updating database table for Chair ID = " sNewID
End If
'set new ID to local setting
m_sID = sNewID
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub_Exit_Done:
'return success value
CreateChair = True
On Error Resume Next
'destroy objects
Exit Function
Sub_Error_Handler:
ProcessErr " Failure Creating Chair. ID = " sNewID
End Function
При вызове функции CreateNewID генерируется новый ID объекта "стул". CreateNewID вызывает функцию New(), форматирует значение в виде
уникального числа и преобразует его в строку. В листинге 1.8 приведен
исходный код функции CreateNewID. Данный алгоритм имеет большой
недостаток. Он генерирует уникальную строку ID только в том случае,
если запрос выполняется через 1 с после предыдущего запроса ID. Для
получения уникальных значений необходимы более приемлемые подходы,
например, использование функции глобально уникального идентификатора
Windows (GUID) или других самодельных функций с генератором случайных
чисел. Этот недостаток не был устранен, чтобы класс clsChair стабильно
генерировал ошибку при записи информации в базу данных. Ошибка
возникает из-за того, что ID объекта "стул" является главным ключом в
таблице базы данных, в которой находится информация об этом объекте.
Запись строки, содержащей такое же значение ID, что и записанное ранее,
приведет к ошибке обновления ADO.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'CreateNewID 'creates a new ID for a new chair ' 'in: nothing 'out: returns string ID for Chair '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Private Function CreateNewID() As String Const NOW_TIME_FORMAT = "yyyymmddhhmmss" Dim sDateTime As String 'get a time data stamp sDateTime = CStr(Format(Now, NOW_TIME_FORMAT)) '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'Note: This algorithm has a huge flaw. 'It does not create unique IDs if more than 'one is requested in a given second. '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'return value CreateNewID = sDateTime End Function
После генерации ID конструируется выражение SQL с использованием
констант, являющихся частью выражения обновления SQL, с помощью
которого новые данные записываются в базу данных. Использованное
значение color в действительности является локальным значением m_scolor. Свойство color, как и me.color, можно (и нужно) использовать
вместо локального значения m_scolor. Если свойство color нужно
подтвердить или изменить из его текущего состояния в экземпляре класса,
то оно пригодится для внесения небольшого изменения в код в
единственном месте, однако в этом случае потребуется изменить код и в
свойстве, и в функции при помощи переменной m_scolor.
После построения команды SQL функция ExecuteCommand передает эту
команду в базу данных для выполнения (см. листинг 1.9). В этой функции
не предусмотрен возврат значения от события. При выполнении операции ExecuteCommand использует ADO.
Для работы с технологией ADO в набор ссылок проекта ConfigSeat нужно
добавить ссылку на ADO. ADO инсталлируется при помощи пакета Microsoft
Data Access Components (
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'ExecuteCommand
'sends a SQL command text to the datasource
'without expectation of return value
'
'in: vsSource - SQL string to execute
'out: returns true on success, false otherwise
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Private Function ExecuteCommand(ByVal vsSource As String) _
As Boolean
On Error GoTo Sub_Error_Handler
Const ERROR_MESSAGE_INFO = "ExecuteCommand"
Dim cmdRequested As ADODB.Command
'establish connection
If m_Connection.State <> adStateOpen Then
Err.Raise 1001, ERROR_MESSAGE_INFO, _
"Connection Object is not open. Database connect be opened."
End If
'establish command
Set cmdRequested = CreateObject("ADODB.Command")
Set cmdRequested.ActiveConnection = m_Connection
'set up command object
cmdRequested.CommandType = adCmdText
cmdRequested.CommandText = vsSource
'run SQL
cmdRequested.Execute
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub_Exit_Done:
'return success value
ExecuteCommand = True
On Error Resume Next
'destroy objects
Set cmdRequested = Nothing
Exit Function
Sub_Error_Handler:
ProcessErr " Failure executing SQL command."
End Function
В большей части вызовов Err.Raise, выполняемых при возникновении
исключительных ситуаций, выводится номер ошибки 1001. Можно указать
любой номер, однако это число выбрано для простоты. Используйте числа
из диапазона 1000 – 65535, предназначенного для нумерации особых
ошибок. Объект ADO Command предназначен для вызова сервера базы данных.
Если от объекта Command ожидается набор записей Recordset, то функция Execute возвращает набор записей ADO Recordset. Так как объект ExecuteCommand изначально не предназначен для возврата набора записей Recordset, объект Recordset, возвращаемый от объекта Command,
игнорируется.
ExecuteCommand проверяет, что локальный объект подключения m_Connection
установлен и жизнеспособен. После этого создается объект Command и
настраивается на отправку серверу команды SQL. Если во время выполнения ExecuteCommand возникнет ошибка, обработчик ошибок зафиксирует ее и
выйдет из функции, возвратив значение "ложь". Все переменные типа boolean в VB имеют значение "ложь", если им не присвоены иные значения,
поэтому включите в программу код, присваивающий функции значение
"истина" по достижении успеха.
Функция OpenChair открывает набора записей ADO Recordset по известному
ID объекта "стул", переданного функции, и заполняет экземпляр класса по
результатам перемещения к первой записи набора Recordset. В листинге
1.10 приведен исходный код функции OpenChair. Так как ID объекта
"стул" является уникальным в базе данных, то ввиду ограничений работы с
данными безопаснее считать, что функция возвращает только одну строку
данных, и, как правило, следует использовать именно первую строку. Recordset исследуется на наличие данных с помощью проверки MoveFirst в пустом
наборе Recordset приведет к ошибке. Свойства EOF или Recordset в одном из
направлений при помощи команд MoveNext или MovePrevious.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'OpenChair 'Opens an existing record for a chair and 'populates the object with the values ' 'in: Chair ID to open 'out: returns true on success and false otherwise '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public Function OpenChair(ID As String) As Boolean On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "OpenChair" Const COMMAND_PREFIX = "SELECT * FROM tblChair WHERE ([ID]='" Const COMMAND_SUFFIX = "')" Dim sSQL As String Dim rs As ADODB.Recordset 'build the insert statement sSQL = COMMAND_PREFIX ID COMMAND_SUFFIX 'get Recordset Set rs = GetADORecordSet(sSQL) 'make certain we got a valid Recordset If rs Is Nothing Then Err.Raise 1001, ERROR_MESSAGE_INFO, _ "Failure Opening Chair ID = " ID End If 'make certain that we got a Recordset 'with at least 1 value If rs.EOF And rs.BOF Then Err.Raise 1001, ERROR_MESSAGE_INFO, _ "Failure - record for Chair does not exist. ID = " ID End If rs.MoveFirst 'set new ID to local setting m_sID = rs(CHAIR_ID) 'set new color to local setting color = rs(CHAIR_COLOR) '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done: 'return success value OpenChair = True On Error Resume Next 'destroy objects Set rs = Nothing Exit Function Sub_Error_Handler: ProcessErr "Failure Opening Chair ID = " ID End Function
Набор Recordset, полученный для OpenChair, создан другой
вспомогательной ADO-функцией – GetADORecordSet. Как и ExecuteCommand, GetADORecordSet воспринимает выражение SQL как параметр и открывает
набор Recordset из источников данных в локальном экземпляре m_Connection объекта Connection. Объект набора записей передается в
вызывающую функцию. В листинге 1.11 приведен исходный код функции GetADORecordSet.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'GetADORecordSet
'Sends SQL command to datasource and returns
'an ADO Recordset to the function consumer
'
'in: vsSource - SQL string to execute
'out: returns true on success, false otherwise
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Private Function GetADORecordSet(ByVal vsSource As String) _
As ADODB.Recordset
On Error GoTo Sub_Error_Handler
Const ERROR_MESSAGE_INFO = "GetADORecordSet"
Dim rsRequested As ADODB.Recordset
Dim cmdRequested As ADODB.Command
'establish connection
If m_Connection.State <> adStateOpen Then
Err.Raise 1001, ERROR_MESSAGE_INFO, _
"Connection Object is not open. Database connect be opened."
End If
'establish command
Set cmdRequested = CreateObject("ADODB.Command")
Set cmdRequested.ActiveConnection = m_Connection
'set up command object
cmdRequested.CommandType = adCmdText
cmdRequested.CommandText = vsSource
'Create instance of Recordset object
Set rsRequested = cmdRequested.Execute
'return Recordset
If Not rsRequested Is Nothing Then
If rsRequested.State = adStateOpen Then
Set GetADORecordSet = rsRequested
Else
'rsRequested state is not open
Err.Raise 1001, ERROR_MESSAGE_INFO, _
" Recordset state is not open " vsSource
End If
Else
'rsRequested is nothing error
Err.Raise 1001, ERROR_MESSAGE_INFO, _
" Recordset object is nothing " vsSource
End If
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub_Exit_Done:
'return value
On Error Resume Next
'destroy objects
Set rsRequested = Nothing
Set cmdRequested = Nothing
Exit Function
Sub_Error_Handler:
ProcessErr " Failure obtaining Recordset."
End Function
Существует много возможностей по усовершенствованию функции GetADORecordSet. Одной из них является установка набора ADO Recordset
как параметра функции, передаваемого в ByRef, и возврат значения
"истина" или "ложь" в зависимости от результата извлечения набора Recordset. Программа расходует ресурсы на создание набора записей ADO Recordset только один раз, и функция сообщит вызывающей функции о
правильности набора Recordset. Функции ExecuteCommand и GetADORecordSet
можно объединить в одну.
Функция GetChairState создает документ XML, описывающий экземпляр
класса clsChair. XML является простым одноэлементным документом.
Элемент Chair содержит два атрибута: ID и Color. Для использования
объекта XML добавьте в проект ссылку на библиотеку MSXML (см. рис.
1.7). В нашем проекте выбрана библиотека Microsoft XML v3.0, но
существуют и другие версии этой библиотеки. На момент публикации книги
уже вышла четвертая версия. В подпрограмме применяется конкатенация
строк для построения XML и возврата строки из класса. Однако такой
подход опасен, поскольку в большинстве XML-анализаторов сразу возникнет
ошибка при некорректности любой части XML. Создание XML с
использованием анализатора позволит правильно построить XML. В листинге
1.12 приведен исходный код функции GetChairState.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' ChairID - read only '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public Property Get ChairID() As String ChairID = Trim(m_sID) End Property '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'GetChairState 'serializes object state into XML DOM 'to look like this <Chair ID="" Color="" /> ' 'in: nothing 'out: returns DOMDocument30 object filled '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public Function GetChairState() As DOMDocument30 On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "GetChairState" Const CHAIR_ELEMENT = "Chair" Const CHAIR_ID_ATTRIBUTE = "ID" Const CHAIR_COLOR_ATTRIBUTE = "Color" Dim xmlChair As MSXML2.DOMDocument30 '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'note : Constructing the XML using 'string concatenation and using the 'XML object to validate is another 'strategy often times used. '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'refresh the object OpenChair Me.ChairID 'build XML document Set xmlChair = New DOMDocument30 'create the element for Chair Set xmlChair.documentElement = _ xmlChair.createElement(CHAIR_ELEMENT) 'add the Chair attributes xmlChair.documentElement.setAttribute _ (CHAIR_ID_ATTRIBUTE), ChairID xmlChair.documentElement.setAttribute (CHAIR_COLOR_ATTRIBUTE), color '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done: 'return object Set GetChairState = xmlChair On Error Resume Next 'destroy objects Set xmlChair = Nothing Exit Function Sub_Error_Handler: ProcessErr " Failure serializing chair into XML. " End Function
После изучения кода в листинге 1.12 становится ясно, почему при
построении XML используется конкатенация строк. Применение DOM Document
интуитивно непонятно, и кажется, что для построения форматированной
строки выполняется очень большой объем работы. Первая версия библиотеки
XML MSXML.DLL была медленной и неэкономичной с точки зрения ресурсов;
здравомыслящий программист реализует XML гораздо быстрее конкатенацией
строк. Язык VB не достаточно эффективен для этого. Сокращение
изменений, вносимых в строку, кардинально улучшает производительность.
Поскольку технологии, связанные с XML, являются довольно новыми,
программное обеспечение, поддерживающее эти технологии, должным образом
не "устоялось". Программист должен быть в курсе новых данных от
производителя и авторов статей и книг, так как данная технология
постоянно модернизируется.
Новый класс clsChair можно протестировать после расширения тестовой
структуры (см. рис. 1.8) для проверки созданного интерфейса. В
тестовую структуру были добавлены кнопки Get XML (Получить XML), Open
(Открыть) для открытия нового экземпляра объекта "стул" и Create
(Создать) (см. рис. 1.19). Перед нажатием на кнопку Open (Открыть)
укажите в текстовом поле аргумент стула ID.
(рис 1.19) Расширенная тестовая структура для clsChair
Если при перекомпиляции ConfigSeat.dll не скомпилирована тестовая
структура, то может возникнуть ошибка при создании экземпляра класса.
Это возможно для любого COM-объекта, если другая программа использует
COM-объект и содержит ссылки на него. В VB проект ActiveX DLL
настраивается на совместимость с проектом по умолчанию во вкладке
Component (Компонент) окна свойств проекта. При перекомпиляции
рассматриваемого проекта ActiveX DLL не будет установлена совместимость
с двоичными файлами, поэтому при выполнении других программ со
скомпилированными ссылками на библиотеку ActiveX DLL возникнут ошибки.
Для иллюстрации вышесказанного рассмотрим следующую ситуацию: ConfigSeat.dll скомпилирована в 9:00 утра. В полдень скомпилирована
тестовая структура с именем testconfigseat.exe. Тестовая структура testconfigseat.exe содержит определенные ссылки на ConfigSeat.dll, и в
ее коде класс озаглавлен строго определенным образом. В 18:00 проект ConfigSeat.dll перекомпилирован и установлена совместимость с проектом.
При выполнении в 18:08 файл testconfigseat.exe вызвал ошибку, поскольку
не смог найти библиотеку ConfigSeat.dll из-за изменения CLSID. При
каждой компиляции ConfigSeat без указания совместимости с двоичными
файлами генерируется новый CLSID. После настройки компонента на
совместимость с двоичными файлами (см. рис. 1.20) VB использует один и
тот же CLSID при каждой компиляции DLL, поэтому любое зависимое от
библиотеки программное обеспечение работает исправно.
Приложение, использующее библиотеку ActiveX DLL, ожидает интерфейс для данного CLSID. Изменение интерфейса класса иначе, чем добавлением новой функции или свойства, вызовет ошибки в приложениях-потребителях, работа которых основывается на классе.
(рис 1.20) Во вкладке Component (Компонент) окна свойств проекта установлена совместимость с двоичными файламиВы можете добавить новые функции, однако нельзя изменить или удалить имеющиеся параметры. Для имени библиотеки и класса идентификатор CLSID остается неизменным, что достигается компиляцией, совместимой с двоичными файлами. Преимуществом совместимости с проектами является то, что программист может ссылаться на проект ActiveX DLL и легко изменять интерфейсы внутренних классов. Поскольку при программировании интерфейс меняется, совместимость с проектами позволит VB разрешить изменения, не предупреждая о нарушении совместимости при удалении или редактировании общей функции.
ConfigSeat.dll можно скопировать в среду сервера и разместить в
приложении COM+, заменив предыдущую версию ConfigSeat.dll. Приложение
COM+ в службах компонентов может заблокировать DLL. После отключения
приложение в службах компонентов библиотека DLL освобождается для
удаления. Если библиотека DLL участвует в работе веб-приложения, то
веб-сервер не будет использовать класс clsChair после удаления классов
в DLL из приложения COM+.
Сейчас мы выполним загрузку новой версии clsClass в приложение COM+ New
ConfigSeatWeb.
ConfigSeat.clsClass, щелкнув правой кнопкой мыши на компоненте и выбрав
Delete (Удалить).ConfogSeat.clsClass.IObjectConstruct_Construct, приведенной в листинге 1.4. В классе ConfigSeat.clsClass строка конструктора содержит строку подключения ADO
для получения доступа к информации в базе данных (см. рис. 1.18).clsChair загружен, выполнив на нем быстрый
модельный тест. Тестовая структура проясняет функциональность класса
внутри новой среды. Исполняемый файл скопируйте на узел и запустите.
Выполните более простой тест с помощью DescribeChair.asp (см. листинг
1.2), добавив несколько новых вызовов функций для нагрузки компонента.
В листинге 1.13 приведена расширенная версия файла DescribeChair.asp с
именем DescribeChairFinal.asp.<%@ Language=VBScript %>
<HTML>
<HEAD>
</HEAD>
<BODY>
<%
dim i
dim o
dim oXML
Response.Write("<p>start Test</p>")
'create the object since this is hard work
set o = Server.CreateObject("ConfigSeat.clsChair")
'demonstrate that values were changing
Response.Write("<p> color=" o.color "</p>")
Response.Write("<p>change color to blue</p>")
o.color = "blue"
Response.Write("<p> color=" o.color "</p>")
if o.CreateChair() then
Response.Write("<p> new id=" o.ChairID "</p>")
else
Response.Write("<p> possible error=" o.ChairError "</p>")
end if
set oXML = o.GetChairState()
Response.Write("<p> xml=" oXML.XML "</p>")
Response.Write("<p> open new chair</p>")
if not o.OpenChair("20021129095221") then
Response.Write("<p> possible error=" o.ChairError "</p>")
end if
Response.Write("<p> new chair color should be purple</p>")
Response.Write("<p> new chair color =" o.color "</p>")
'destroy object so it can be created again
set o = nothing
%>
</BODY>
</HTML>
Запустите тест нагрузкой из утилиты Microsoft Application Center Test,
и вы увидите, что работа приложения ASP – COM – база данных требует
больше ресурсов, чем простое приложение ASP – COM. Предыдущая версия clsChair не предусматривает взаимодействия с базой данных, и база
данных располагается на том же сервере, где расположены ASP и
COM-объект clsChair. При моделировании одновременной работы 100
пользователей в течении 5 минут выяснилось, что приложение способно
поддерживать среднюю нагрузку, равную 45 запросам на страницы в
секунду.
На рисунке 1.17 показано окно служб компонентов, отображающее
состояние предыдущего теста. В тесте для предыдущей версии clsChair
заголовки Call и не регистрировали никаких значений, кроме 0.
В последней версии clsChair поле In Call стабильно отображало значения
от 0 до 1, а поле стало равным 15 мс. Очевидно, что
производительность компонента заметно снизилась по сравнению с
проведенным ранее тестом. Как видите, дополнительная функциональная
нагрузка, связанная со считыванием информации из базы данных, снижает
эффективность работы веб-приложения.
Класс clsChair поддерживает обобщение логики представления. Функция GetChairState создает упорядоченную версию объекта "стул" потребителю,
осуществляющему построение страницы. Как правило, веб-приложения COM
используют ASP-страницу для анализа представления HTML, реализации
классов и упрощения прорисовки страницы посредством связывания
XML-объектов с документами XML, необходимыми для построения страницы. В
ситуации COM – ASP – XSL (или XSLT) можно создать многозвенное
приложение, обобщающее типы логики и технологии, приведенные в таблице
1.1.
| Название звена | Поддерживаемая технология |
|---|---|
| Логика представления | Лист XSL или XSLT |
| Бизнес-логика | VB COM и ASP. |
| Логика доступа к данным | ADO |
| Логика данных | SQL Server |
Страница ASP является уникальной частью программного решения, поскольку
объединяет бизнес-логику и логику представления. В программном решении,
представленном выше, ASP не была чистым обобщением бизнес-звена или
звена представления, поскольку содержала аспекты каждого из них. В
листинге 1.14 приведен исходный код страницы-диспетчера ASP,
использовавшейся с clsChair. XMLCOMChair.asp не содержит кода HTML, вся
страница отображается на листе XSL. Независимо от способа отображения
данных из clsChair в браузере, ASP не требует внесения изменений. ASP
должна иметь сведения об интерфейсе класса clsChair, поэтому в код
включена бизнес-логика. Если в класс clsChair добавляются новые функции
или свойства, то нужно отредактировать код ASP. ASP легко
параметризуется в соответствии с настраиваемой системой запуска
классов, полностью абстрагируясь от бизнес-логики и логики
представления.
<%@ Language=VBScript %>
<%
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
' Drawpage
' handles XML transformation
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub Drawpage(sXML)
CONST XSL_FILE = "formatChair.xsl"
dim oXML
dim oXMLXSL
Set oXMLXSL = Server.CreateObject("Microsoft.XMLDOM")
Set oXML = Server.CreateObject("Microsoft.XMLDOM")
'load XML
oXML.loadXML(sXML)
'load the XSL
oXMLXSL.load(Server.MapPath(XSL_FILE))
'write the page
Response.Write(oXML.transformNode(oXMLXSL))
'destroy object
set oXML = nothing
set oXMLXSL = nothing
end sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
' main
' dispatches calls
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub Main()
dim o
dim XMLDOM
'create the object chair
set o = Server.CreateObject("ConfigSeat.clsChair")
'check for color setting
if len(Request("color"))>0 then
o.color = Request("color")
end if
'decide what to do
select case Request("Action")
case "New"
o.CreateChair
case "Open"
o.OpenChair Request("ID")
end select
'get the object state
set XMLDOM = o.GetChairState()
'write the page
Drawpage XMLDOM.XML
'destroy object
set o = nothing
set XMLDOM = nothing
end sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
' Script entry point
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
Main()
%>
После выполнения экземпляром класса clsChair своей бизнес-логики
состояние clsClass преобразуется в XML и используется для построения
страницы HTML. Имя листа XSL – formatChair.xsl – хранится в коде ASP,
но его можно получить другим способом, например, с помощью аргументов
HTTP в представлениях форм или ссылках. Подпрограмма Drawpage при
помощи строкового аргумента, содержащего XML, прорисовывает конечную
веб-страницу. Лист XSL определяет способ построения веб-страницы и
отображение значений в XML. В XSL можно расположить и другие данные,
например, сценарии JavaScript, предназначенные для выполнения в
браузере. В листинге 1.15 приведен код листа XSL formatChair.xsl.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <xsl:template match="/"> <xsl:comment> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ XSL Sheet primarily for the purposes of building an HTML page to allow a user to open or create a new chair and see the results with the presentation logic abstracted completely ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ </xsl:comment> <xsl:comment> Start the HTML page here </xsl:comment> <HTML> <HEAD> <TITLE>XML COM page</TITLE> </HEAD> <BODY> <xsl:comment> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ build table for chair data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ </xsl:comment> <xsl:for-each select="Chair"> <P>current</P> <TABLE BORDER="1" CELLSPACING="0" CELLPADDING="0"> <TR> <TH>ID</TH> <TH>Color</TH> </TR> <TR> <TD><xsl:value-of select="@ID"/></TD> <TD><xsl:value-of select="@Color"/></TD> </TR> </TABLE> </xsl:for-each> <xsl:comment> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ XSL parts are completed Please never forget, all HTML must be well formed also. XSL is also case sensitive. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ </xsl:comment> <P>command </P> <xsl:comment> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ build table for commanding new chair data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ </xsl:comment> <FORM METHOD = "POST" ACTION = "XMLCOMChair.asp" ID = "frmImage" NAME = "getInfo" > <TABLE BORDER="1" CELLSPACING="0" CELLPADDING="0"> <TR> <TD>Action</TD> <TD> <input TYPE="text" NAME="Action" VALUE="Open or New"> </input> </TD> </TR> <TR> <TD>ID</TD> <TD><input TYPE="text" NAME="ID" VALUE=""></input></TD> </TR> <TR> <TD>color</TD> <TD> <input TYPE="text" NAME="color" VALUE="puce"> </input> </TD> </TR> </TABLE> <input ID="subFull" NAME="subR" TYPE="submit" VALUE="Go"></input> </FORM> </BODY> </HTML> </xsl:template> </xsl:stylesheet>
При XSL-программировании следует иметь в виду несколько важных моментов. Любой файл XSL должен быть правильно сформирован, т.е. соответствовать стандартам XML, принятым Консорциумом WWW (W3C). Ошибки в формировании файлов, как правило, вызываются следующими проблемами в коде XML.
Редакторы XML позволяют обнаружить больше ошибок при формировании XML. Пользуйтесь редактором XML для упрощения диагностики ошибок в программном решении, использующем XML, или для разработки программного обеспечения, реализующего построение XML. При неправильном формировании документа XML никакая конструкция, требующая этот документ, работать не будет. Существующие на сегодняшний день анализаторы XML не дают подробной информации о причине ошибки, поэтому поиск проблемы может оказаться затруднительным.
Когда программное решение целиком отгружено на сервер, и браузер
запрашивает XMLCOMChair.asp, то отображаемая страница должна иметь
следующий вид (см. рис. 1.21).
(рис 1.21) XMLCOMChair.asp использует clsChair и formatChair.xsl для
прорисовки веб-страницы
В XML для описания данных используется обычный текст, поэтому возможны
проблемы, связанные с расшифровкой данных из структуры XML. Возьмем, к
примеру, имя сотрудника компании O'Brien. Что произойдет, если
программа поместит список сотрудников, в который входит и O'Brien, в
документ XML, предназначенный для отображения в браузере? Элемент XML
будет выглядеть так: <имя сотрудника="O'Brien">. Если апостроф не будет
закодирован как специальный символ, то в анализаторе XML при загрузке
кода произойдет ошибка. При кодировании специальных символов
соответствующим образом элемент XML примет вид: <имя
сотрудника="Oapos;Brien">.
Многие символы требуют кодирования. Специальные символы представляются в виде числовых ссылок из набора символов ISO/IEC 10646. Некоторым символам присвоены специальные знаковые последовательности, вид которых соответствует обозначаемому символу.
| Символ | Последовательность знаков общей сущности |
|---|---|
| amp; | |
| < | lt; |
| > | gt; |
| ' | apos; |
| " | quot; |
Например, числовая ссылка на символ "" имеет вид "#38;", можно использовать и представление "amp;". Числовым представлением символа "=" является "#61;". Для данного символа отсутствует знаковая последовательность. Для получения информации о других символах и эквивалентных им представлениях обратитесь к Приложению. Дополнительная информация по XML приведена на странице http://www.w3.org/TR/REC-xml, где можно ознакомиться с W3C-спецификацией для XML.
Модель компонентных объектов (Component Object Model, COM) – это спецификация, разработанная компанией Microsoft для построения программных компонентов, используемых приложениями или программами Windows для расширения своих функциональных возможностей. С помощью COM программное обеспечение, написанное на одном языке (например, на C++), может работать с программой, написанной на другом языке (скажем, на Visual Basic), без перекомпиляции программных компонентов. Это означает, что динамически подключаемую библиотеку, разработанную в C++, можно вызывать из исполняемого файла, написанного на Visual Basic. При работе с активными серверными страницами (ASP) VBScript может вызвать функцию из объекта COM, созданного при помощи языка VB, C++ или любого другого. Веб-разработка с использованием технологии COM осуществляется посредством вызова в ASP функций, расположенных в COM-объектах.
Аббревиатура
Примечание. Термин "потребление" часто используется, когда речь идет о вызове программного обеспечения динамически подключаемой библиотеки (DLL) или другой библиотеки. Этот термин появился в результате изменения терминологии "клиент-сервер", описывающей взаимодействие между клиентом базы данных (программой, осуществляющей запрос или ввод данных) и самой базой. Термины "потребитель" и "провайдер" стали нормой при описании программных компонентов; они отражают процесс взаимодействия между программой, которая базируется на другой программе, и программой, которая обслуживает другую программу.
В отличие от обычного ASP-программирования (см. лекцию 12 курса "Администрирование web-серверов в IIS"), в COM-программировании активные серверные страницы используются в качестве системы организации. ASP упорядочивают HTTP-запросы в команды, осуществляют потребление COM-объектов, непосредственно выполняющих работу, и возвращают ответ клиенту. Преимуществом такого подхода является то, что программа в COM-объекте инкапсулирована в виде единого дискретного элемента, который можно целиком добавить или удалить из системы. Программное обеспечение разрабатывается таким образом, что программисты могут его использовать, но не могут изменять, поскольку к дистрибутиву исходный код не прилагается. В зависимости от языка построения COM-объекта заложенные в программу машинные инструкции могут быть двоичными, выполняемыми с большей производительностью, чем языки сценариев VBScript в ASP.
Архитектура типичного COM-приложения показана на рис. 1.1.
В настоящее время COM-программирование заключается в написании библиотек DLL ActiveX с помощью языка Visual Basic 6 (VB6). Хотя объекты COM можно создавать с помощью других языков, в данной лекции мы будем работать с VB6. Проект VB6 компилируется в обычный исполняемый файл, что полностью избавляет программиста от трудностей, присущих работе с языком описания интерфейса COM (IDL) и управлению архитектурой самого объекта. VB6 является стандартным языком программирования, интегрированная среда разработки (IDE) довольно проста, и поэтому любой пользователь напишет, скомпилирует и запустит программу без особых трудностей.
(рис 1.1) Архитектура веб-приложения COMПримечание. Библиотека ActiveX DLL в VB6 является шаблоном проекта для создания COM-объекта.
После запуска Visual Basic 6 отображается диалоговое окно New Project (Новый проект) (см. рис. 1.2), в котором выбирается тип проекта. Для построения COM-объектов веб-приложения выберите ActiveX DLL и нажмите на кнопку Open (Открыть).
(рис 1.2) Диалоговое окно нового проекта в Visual Basic 6В VB6 можно создать проекты других типов, например, исполняемые файлы и
элементы управления ActiveX. Проекты ActiveX EXE и Standard EXE обычно
используются при разработке приложений. Проект исполняемого файла мы
рассмотрим далее при создании
Из-за ограничений, связанных с разработкой программ в VB runtime, элементы управления ActiveX, написанные на VB, не подходят для веб-разработки, поскольку после установки программы на клиенте зачастую требуется перезагрузка компьютера для работы с новым элементом управления ActiveX.
После выбора типа проекта будет создан новый проект с именем Project1 и
новый класс Class1. Если сразу скомпилировать проект, то конечный файл
будет называться по умолчанию Project1.dll, а идентификатор класса
(CLSID), используемый для идентификации класса в команде ASP Server.CreateObject – Project1.Class1. Имена класса и проекта должны
быть информативными, а не шаблонными именами по умолчанию. Классу
следует присвоить имя применительно к сути создаваемого проекта, а
проекту – имя, определяющее файл хранилища или исполнения, внутри
которого будет находиться класс.
Примечание. Все COM-объекты, созданные с помощью проекта Active X DLL в
VB6, имеют расширение .dll.
Пусть в нашем примере веб-приложение является частью интернет-проекта
по выбору параметров мебели с именем ConfigSeat.
Объект "стул" определен в процессе сбора требований, а создаваемый
класс предназначен для представления этого объекта и является частью
бизнес-логики программного приложения. Данный класс логично назвать clsChair. Префикс cls определяет объект как класс. Элемент Auto List
Members в функции Visual Basic IntelliSense отображает имена частей
проекта и не различает классы и другие типы файлов, например, модули.
Использование префикса cls облегчает идентификацию класса в списке Auto
List Members.
Для изменения имени класса откройте окно свойств с помощью команды
View\Properties Window (Вид\Окно свойств) и выберите класс в Project
Explorer (Диспетчер проектов). Исправьте имя Class1 в области Name
(Имя) на clsChair (см. рис. 1.3). (Остальные параметры в окне свойств
не меняйте, поскольку для этого требуются глубокие знания процесса
разработки VB ActiveX. В данной лекции этот вопрос не рассматривается.)
Вы можете также изменить имя проекта, щелкнув правой кнопкой мыши на имени проекта в Project Explorer (Диспетчер проектов).
(рис 1.3) Окно свойств классаВ диалоговом окне свойств проекта во вкладке General (Общие) имеется
текстовое поле Project Name (Имя проекта), в котором отображается имя
по умолчанию Project1. В нашем примере назовем проект ConfigSeat.
Удалите в текстовом поле имя Project1 и введите ConfigSeat (см. рис.
1.4).
Многие программисты не знают о существовании автоматической нумерации версий в VB6. Номера версий помогают определять последнюю версию разрабатываемой библиотеки DLL с помощью уникальных идентификаторов. При каждой компиляции программного кода номер версии увеличивается. Как правило, объект COM устанавливается на узел несколько раз. Потребители программного обеспечения должны использовать только одну версию (последнюю), и номера версий позволяют работать именно с этой версией. При отсутствии номеров версий для определения последней версии пришлось бы использовать дату создания файла. В некоторых ситуациях (особенно при совместной работе над проектом нескольких программистов) определение номера версии по дате не работает. Для включения автоматического присвоения номеров новым версиям проекта откройте вкладку Make (Создание) в диалоговом окне свойств проекта и отметьте опцию Auto Increment (Автоматическая нумерация). Если вы не сделаете это, ошибки в программе не возникнет. Опция Auto Increment (Автоматическая нумерация) по умолчанию не включена, но мы настоятельно рекомендуем включать ее в каждом проекте.
(рис 1.4) Диалоговое окно свойств проекта с новым именем ConfigSeat
Объект "стул" имеет некоторые атрибуты: цвет, высота, наличие или
отсутствие колес. Эти атрибуты можно присоединить к классу в виде
свойств. Ниже показано, как расширить класс clsChair добавлением
свойства color.
Let и Get.
(рис 1.5) Диалоговое окно Add Procedure (Добавление процедуры)Свойством называется специальная ConfigSeat, а в списке Classes (Классы) в левой части окна содержится
класс clsChair.
(рис 1.6) Браузер объектов отображает класс clsChair и свойство сolor
Выберите класс clsChair, чтобы отобразить добавленное свойство color в
правой области. Выделите свойство color, и в нижней части окна в
области отчета появится детальное описание этого свойства с указанием
типа, класса и библиотеки, которым оно принадлежит.
Свойство color в его текущем состоянии является практически
бесполезным, так как для его значений еще не определены переменные. Без
этих переменных установка значения свойства не позволит ни сохранить
значение, ни получить его. Свойство используется для изменения значения
в классе, которое находится в памяти при работе класса, поэтому нужно
объявить локальную переменную с областью действия, охватывающей весь
класс.
Значение color представляет собой строку, описывающую цвет стула,
поэтому в верхней части кода класса объявим частную (private) строковую
переменную с именем m_scolor. Ключевое слово private означает, что
переменная недоступна программе за пределами класса. Область действия private целесообразно использовать при контроле доступа потребителей к
членам класса, свойствам, подпрограммам и функциям. При работе возможна
ситуация, когда потребуется изменить другие значения класса или
проверить цвет при его установке. Если локальная переменная m_scolor
будет общей, то потребитель класса сможет изменить ее значение, не
поставив в известность класс.
Рекомендуется всегда использовать свойства для разрешения установки или считывания атрибута в классе. Данный подход несколько затрудняет программирование и повышает уровень сложности программного решения, однако в будущем будет проще вносить изменения в класс. Если правила работы класса поменяются, то обновление объекта COM гораздо легче реализовать под общим интерфейсом COM, поскольку код, лежащий в основе функций свойства, используется для корректировки атрибута класса без изменения общего интерфейса класса. Изменение интерфейса класса потребует изменения потребителей класса, поэтому сложности из-за отсутствия абстракции между внутренними членами класса и его внешним интерфейсом, окажутся более серьезными по сравнению с первоначальным усложнением проекта.
В листинге 1.1 приведен код, реализующий класс clsChair.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' constants to class Private Const DEFAULT_COLOR = "Brown" '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' locals to class 'holds the color of the chair Private m_scolor As String '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public Property Get color() As Variant color = m_scolor End Property Public Property Let color(ByVal vNewValue As Variant) m_scolor = vNewValue End Property Private Sub Class_Initialize() 'set default color on instantiation m_scolor = DEFAULT_COLOR End Sub
Вверху каждого файла кода в VB рекомендуется размещать выражение Option
Explicit. Оно проверяет все необъявленные переменные, используемые в
коде, при компиляции. При обнаружении таких переменных VB прерывает
компиляцию и генерирует сообщение об ошибке. Данное выражение позволяет
принудительно объявлять переменные, что полезно для выявления опечаток
в именах переменных. Можно провести долгие часы, пытаясь понять, почему
переменная не содержит нужного значения, и в результате обнаружить, что
эта переменная просто неправильно указана в строке кода. Выявить такие
ошибки трудно, поэтому используйте команду Option Explicit. VB
настраивается на автоматическое добавление данного выражения в код
каждого файла с помощью команды Tools\Options (Сервис\Параметры).
Откройте вкладку Editor (Редактор) и отметьте опцию Require Variable
Declaration (Требовать объявление переменных).
Любое программное обеспечение необходимо тестировать, и VB IDE для этого имеется прекрасный механизм. Нажмите на кнопку Start (Пуск) в панели инструментов VB либо на клавишу F5, чтобы откомпилировать и выполнить программу.
Поскольку проект ConfigSeat является библиотекой ActiveX DLL, его
нельзя выполнить, т.к. он должен использоваться другой исполняемой
программой. Для тестирования класса clsChair следует создать еще один
проект в том экземпляре IDE, где редактируется clsChair.Это будет
исполняемая программа с одной задачей – тестированием класса clsChair.
Программа для тестирования другой программы называется тестовой
структурой.
Project1, содержащий форму Form1.clsChairTester.clsChair недоступен, поскольку в тестовой
структуре clsChairTester нет ссылки на проект ConfigSeat. Для создания
ссылки выберите команду Project\References (Проект\Ссылки) для открытия
диалогового окна References (Ссылки) (см. рис 1.7(рис 1.7) Диалоговое окно проекта References (Ссылки)ConfigSeat, отметив соответствующую ей
опцию, после чего нажмите на кнопку OK.Запомните. В диалоговом окне References (Ссылки) отображаются ссылки для выбранного в настоящий момент проекта. Изменение ссылок применяется только к этому проекту. Вы можете случайно выделить и другие проекты в группе проектирования, поэтому перед внесением изменений убедитесь в том, что выбрано соответствующее диалоговое окно References (Ссылки) с именем окна активного проекта в строке заголовка.
Элемент form1 можно настроить на отображение функционирования различных
компонентов класса clsChair. Используемый подход заключается в
представлении всех свойств класса в виде текстовых полей, всех функций
– в виде кнопок, с текстовыми полями для аргументов формы тестовой
структуры соответствующего класса. Тестовую структура нужно сохранить
вместе с исходным кодом тестируемого класса, так как в будущем это
поможет при усовершенствовании класса или устранении ошибок.
Примечание. Рассматриваемая тестовая структура – clsChairTester –
сохранена с исходным кодом данной лекцию и доступна на веб-сайте автора
книги.
В классе clsChair имеется только одно свойство, поэтому тестовая
структура просто установит значение свойства и покажет его
пользователю. После добавления в форму нескольких текстовых полей и
командной кнопки, написания кода для создания и управления классом clsChair можно протестировать компонент "стул" с помощью тестовой
структуры.
Brown (Коричневый).На рисунке 1.8 показана тестовая структура, при работе которой цвет стула успешно изменен в нескольких тестах.
(рис 1.8) Тестовая структура clsChair тестирует свойство color
Теперь, когда класс clsChair прошел модульное тестирование в тестовой
структуре, он почти готов для использования в веб-приложении. Однако
перед этим его нужно скомпилировать и разместить на несущем сервере.
Выполните следующие действия.
ConfigSeat.ConfigSeat.dll (Файл\Создать ConfigSeat.dll ).Откроется диалоговое окно Make Project (Создать проект), в котором нужно ввести имя файла и расположение новой библиотеки DLL. Измените имя файла или путь к файлу, если это необходимо, и нажмите на клавишу OK.
VB откомпилирует проект ConfigSeat и создаст файл .dll. Библиотека DLL
автоматически зарегистрируется на узле, и ее можно будет сразу
использовать. (О регистрации DLL речь пойдет в следующем подразделе.)
После копирования библиотеки ConfigSeat.dll на сервер ее необходимо
зарегистрировать или загрузить в службы компонентов как приложение
COM+. Для регистрации компонента компания Microsoft разработала утилиту
командной строки regsvr32.exe. Для работы с ней выполните следующие
действия.
<имя COM DLL> – имя файла
библиотеки COM DLL). Для файла библиотеки ConfigSeat.dll команда имеет
вид regsvr32 ConfigSeat.dll, а курсор командной строки при выполнении
команды должен находиться в той же папке, что и файл ConfigSeat.dll.
При запуске regsvr32 из другого места расположения в команде следует
указать полный путь к файлу .dll на сервере. Например, если файл ConfigSeat.dll расположен в папке C:\bin\, то команда имеет вид regsvr32 C:\bin\ConfigSeat.dll.Для удаления библиотеки DLL COM или замены ее другой библиотекой
следует аннулировать регистрацию библиотеки DLL и удалить
соответствующий файл. При аннулировании регистрации из реестра
удаляется запись CLSID для данной библиотеки, чем достигается "чистота"
реестра и сокращается количество записей. Выполните те же самые шаги, с
помощью которых проводилась регистрация, но используйте в команде ключ /u. Например, для аннулирования регистрации файла C:\bin\ConfigSeat.dll
команда примет вид regsvr32 /u C:\bin\ConfigSeat.dll. Для просмотра
При работе с regsvr32 не возникает каких-либо проблем. Это идеальное программное решение, не требующее управления и дополнительной информации о COM-объекте. Регистрация COM-объектов с помощью regsvr32 прекрасно подходит для приложения рабочего стола.
Установка объекта COM в службах компонентов более предпочтительна для веб-приложений по сравнению с использованием regsvr32, поскольку компоненты веб-приложении зачастую требуют последующего управления и обновления компонентов. Любое программное обеспечение, загруженное в службы компонентов, называется компонентом. Службы компонентов имеют больше возможностей по управлению компонентами, например:
Для загрузки объекта COM в службы компонентов сначала нужно создать приложение COM+. Приложение COM+ содержит один или более объектов или компонентов COM. Приложение COM+ в службах компонентов интерпретируется как идеальный (с точки зрения потребителя) развертываемый модуль. Приложение COM+ может использоваться другим процессом, или процесс, под которым выполняется приложение COM+, может быть предоставлен службам компонентов. Запуск (или остановка) приложения COM+ включает (или запрещает) использование всех его компонентов. Если наряду с надежными компонентами загружены ненадежные, то надежные компоненты нужно переместить в другое приложение COM+, которое не требует такого количества административных изменений, как приложение COM+ с проблемными библиотеками DLL. Такая стратегия минимизирует время простоя компонентов приложения, которое не будет "списано со счета" из-за ошибки в одном-единственном компоненте. Появляется возможность более четкого управления установкой компонента, изолированного от остальных надежных компонентов, пока его надежность не будет доказана.
Ниже приведены шаги, с помощью которых новое приложение добавляется в службы компонентов.
Примечание. С помощью консоли MMC
В первом окне мастера нажмите на кнопку Next (Далее).
(рис 1.9) Добавление нового приложения в консоль управления Components Services (Службы компонентов).В окне Install Or Create A New Application (Установка или создание нового приложения) (см. рис. 1.10) нажмите на кнопку Create An Empty Application (Создать пустое приложение) для перехода к следующему окну.
(рис 1.10) Окно Install Or Create A New Application (Установка или создание нового приложения) мастера установки приложения COM+В окне Create Empty Application (Создать пустое приложение) (см. рис.
1.11) введите имя приложения COM+; в нашем случае – New ConfigSeatWeb.
Имя приложения COM+ не играет особой роли с точки зрения
программирования, оно определяет приложение COM+ в консоли управления
службами компонентов. Библиотека DLL ConfigSeat является новым
компонентом, поэтому выберите значение по умолчанию
(рис 1.11) Окно Create Empty Application (Создание пустого приложения) мастера установки приложения COM+В окне Set Application Identity (Установка принадлежности приложения)
(см. рис. 1.12) параметром по умолчанию является Interactive User
(Интерактивный пользователь). Здесь можно указать одну из встроенных
учетных записей: Local Service (Локальная служба) или
(рис 1.12) Окно Set Application Identity (Установка принадлежности приложения) мастера установки приложения COM+Не используйте этот параметр при работе с несущими компонентами приложения COM+, так как приложение COM+ не будет запускаться после выхода пользователя из системы узла.
Учетная запись
(рис 1.13) Окно Add Application Roles (Добавление ролей приложения) мастера установки приложения COM+Роли создаются из соответствующих учетных записей пользователей Windows. Нажмите на кнопку Add Role для добавления дополнительных ролей в приложение COM+. В данном случае добавлена роль по умолчанию с именем CreatorOwner. Эта роль прекрасно подходит для приложения COM+ в нашем примере. Для продолжения работы нажмите на кнопку Next (Далее).
В окне Add Users To Roles (Добавить пользователей в роли) (см. рис. 1.14) в роли, определенные в окне добавления ролей приложений, можно добавить учетные записи пользователей Windows. По умолчанию ваша учетная запись Windows будет использоваться в каждой роли, определенной в предыдущем окне. Учетные записи Windows, добавленные в роли, предназначены для предоставления аутентификационных данных, под которыми выполняются процессы. Учетная запись Windows webuser – единственная запись, добавленная в роль CreatorOwner (см. рис. 1.14). Нажмите на кнопку Next (Далее) для продолжения работы.
(рис 1.14) Окно Add Users To Roles (Добавление пользователей в роли) мастера установки приложения COM+ с учетной записью, добавленной в роль CreatorOwner.Для понимания различий между серверным приложением и приложением библиотеки в службах компонентов необходимо знать некоторые термины и механизмы архитектуры Windows. Процессом называется исполняемая программа, которая выполняется в данный момент. Операционная система Windows предоставляет процессорное время для каждого порожденного процесса. Нитью называется работа, выполняемая внутри процесса. Процесс может поддерживать одновременно несколько нитей. Если нити в процессе отсутствуют, то процесс считается выполненным, и Windows не выделяет ему процессорное время.
Чем больше процессов выполняется, тем больше ресурсов используется компьютером для обеспечения их работы. Запуск процесса изначально требует значительного количества ресурсов сервера. Остановка одного процесса не влияет на другие процессы, если последние не нуждаются в нем. Остановка процессов является лояльным действием, не представляющим риск для стабильности системы, поэтому распределение большего количества работы между процессами требует большего объема системных ресурсов, но обеспечивает более высокий уровень надежности.
Стремясь к сокращению системных ресурсов, связанных с запуском и работой процессов, программисты разрабатывают программное обеспечение для загрузки в память под существующим процессом вместо создания нового процесса. Сравнение веб-приложений Common Gateway Interface (CGI) и веб-приложений ASP показывает различие, о котором идет речь. Если на веб-странице, требующей работы приложения CGI, наблюдается 10 посещений в минуту, то независимо от сложности этой работы серверу придется запускать исполняемый файл CGI 10 раз в минуту, т.е. 600 раз в час.
Если страница ASP выполняет те же задачи, что и исполняемый файл CGI, то через один и тот же интервал времени запускаются нулевые процессы. На самом деле запускается лишь один процесс, и это происходит при старте сервера; этот процесс – IIS. Расширение ISAPI ASP.DLL работает в пространстве процесса IIS. Раньше службы IIS останавливались без видимых причин после продолжительного периода времени. Подобные ошибки возникали из-за повреждения процесса IIS и его дестабилизации исключением, утечкой памяти или невыпущенными указателями. Причиной этому была загрузка библиотеки DLL с дефектами в пространство процесса IIS. Эта унаследованная особенность (или ошибка) в архитектуре Windows привела к тому, что IIS воспринимается как ненадежная система в сравнении с другими, менее сложными системами, использующими CGI.
Для повышения надежности без потерь производительности (что возможно
при работе программного обеспечения в собственном независимом процессе)
был разработан сервер Microsoft Transaction Server (
Цель создания приложения COM+ – дать возможность службам компонентов
обслуживать экземпляры классов в ConfigSeat.dll. Следующим шагом по
установке ConfigSeat.dll на несущем сервере является добавление
ConfigSeat.dll в только что созданное приложение COM+ New
ConfigSeatWeb.
В консоли управления Component Services (Службы компонентов) щелкните правой кнопкой мыши на папке Component (Компонент) под пунктом приложения COM+ New ConfigSeatWeb и выберите команду New\Component (Создать\Компонент) (см. рис. 1.15).
(рис 1.15) Запуск мастера установки компонентов COM+ConfigSeat.dll и нажмите на
кнопку Open (Открыть).В окне Install New Components (Установка новых компонентов) приведен список компонентов, добавляемых в новое приложение COM+ (см. рис. 1.16 ).
(рис 1.16) Окно Install New Component (Установка нового компонента)
мастера компонентов COM+ с результатом загрузки библиотеки ConfigSeat.dll.
Данное окно предназначено для открытия библиотек COM DLL, загрузки их в приложение COM+ и отображения выбранных элементов. Нажмите на кнопку Add (Добавить) для открытия диалогового окна выбора файла (см. шаг 4). Выбор других библиотек COM DLL добавит их в списки файлов и компонентов, отображаемые в этом окне. Нажмите на кнопку Next (Далее).
ConfigSeat.dll будет добавлена в
приложение COM+ New ConfigSeatWeb.Службы компонентов разрешают ролевой доступ к любому компоненту, загруженному в приложение COM+. Учетные записи пользователей Windows приписываются к роли, и запросы компонента выполняются с помощью аутентификационных данных этих учетных записей. Если эти роли связаны с запрашиваемой частью компонента, то программа-потребитель будет функционировать должным образом; в противном случае она не сможет осуществить доступ к компоненту. Роли связываются с компонентом, загруженным в приложение COM+, на следующих уровнях:
Следует включать ролевой доступ, начиная с верхнего уровня и далее вниз, до нужного уровня контроля доступа. В качестве метода компонента можно определить низшую дискретную функциональность, реализующую контроль доступа. Для включения ролевого доступа выполните следующие шаги.
Чтобы включить проверку доступа уровня компонента для приложения COM+, выполните следующие шаги.
Для включения проверки доступа для компонента нужно включить проверку доступа для приложения COM+ и после этого выполнить следующие шаги.
Для присвоения роли компоненту в целом отметьте роль в списке Roles Explicitly Set For Selected Item(s) (Роли, установленные для выделенных элементов). Все методы компонента унаследуют данную роль.
Для присвоения роли определенным методам внутри компонента отметьте опцию Enforce Component-Level Access Checks (Обязательная проверка доступа на уровне компонента), что позволит в дальнейшем присваивать роли методам компонента.
Для компонента ConfigSeat.clsChair, добавленного в приложение COM+ New
ConfigSeatWeb, ролевой доступ не требуется, поэтому обязательные
проверки доступа уровня компонента не включены. Приложение COM+ New
ConfigSeatWeb, тем не менее, настроено на обязательную проверку
доступа, поэтому проверки доступа компонентного уровня включены. Если
система IIS функционировала под учетной записью по умолчанию, созданной
Windows (например, IUSR_имя_компьютера ), то ASP-программа, создающая
объект ConfigSeat.clsChair, вызовет ошибку, поскольку гостевая учетная
запись интернета не имеет доступа к компоненту ConfigSeat.clsChair.
После смены ее на другую учетную запись с доступом к указанному
компоненту код ASP будет функционировать должным образом. Для
использования кодом ASP компонента ConfigSeat.clsChair веб-сайт или
виртуальный каталог в IIS настроен на работу с использованием
аутентификационных данных учетной записи webuser.
Для настройки доступа выполните следующие шаги.
Теперь страницы ASP будут выполняться под учетной записью webuser. При
создании страницами ASP компонента ConfigSeat.clsChair
аутентификационные данные учетной записи webuser представляются для
запроса в службы компонентов. Службы компонентов проверяют разрешения
учетной записи webuser на создание и использование компонента, и ASP
реализует функции в компоненте ConfigSeat.clsChair.
Для тестирования библиотеки ConfigSeat.dll можно создать несложный код
ASP, реализующий экземпляр класса clsChair для вывода значения color в
браузер и изменения этого значения. Файл ASP DescribeChair.asp (см.
листинг 1.2) можно расположить в веб-приложении на сервере с
библиотекой ConfigSeat.dll. Файл ASP можно расположить на веб-сайте по
умолчанию, созданном при установке IIS. Если сервер не настроен на
выполнение exe-файлов, то проведите соответствующую настройку. Для
получения инструкций по реализации работы ASP в IIS6 обратитесь к лекции 12 курса "Администрирование web-серверов в IIS".
<%@ Language=VBScript %>
<HTML>
<HEAD>
</HEAD>
<BODY>
<%
dim o
Response.Write("<p>start Test</p>")
'create the object since this is hard work
set o = Server.CreateObject("ConfigSeat.clsChair")
'demonstrate that values were changing
Response.Write("<p> color=" o.color "</p>")
Response.Write("<p>change color to blue</p>")
o.color = "blue"
Response.Write("<p> color=" o.color "</p>")
'destroy object so it can be created again
set o = nothing
%>
</BODY>
</HTML>
Для демонстрации возможностей служб компонентов DescribeChair.asp
следует запустить много раз. Нагрузка на веб-сервер, созданная
запросами на файл ASP, не обеспечивает достаточный спрос на компонент
COM или сервер, на котором он расположен, поэтому службы компонентов не
зарегистрируют потребность в ресурсах. Microsoft предлагает две
утилиты, предназначенные для проведения проверки нагрузкой.
WAS – бесплатная программа; Microsoft Application Center Test входит в пакет Visual Studio .NET Enterprise Edition.
Для создания нехватки ресурсов в ASP и просмотра реакции на это условие
в Microsoft Application Center Test был создан простой сценарий,
моделирующий одновременную работу ста пользователей в течение 5 минут.
Такая нагрузка достаточно велика, и службы компонентов испытывали
большую нагрузку при обслуживании экземпляра clsChair. В каждый момент
времени создавалось от нуля до пяти экземпляров clsChair,
обеспечивавших 175 запросов на страницы в секунду. На рисунке 1.17
показана консоль управления службами компонентов, отображающая
состояние класса clsChair при тестировании нагрузкой.
(рис 1.17) Консоль управления службами компонентов, отражающая
использование класса clsChair
До сих пор мы показывали построение простейшего веб-приложения COM,
включая все этапы процесс разработки. В реальном COM-объекте должен
присутствовать набор классов, отражающий объекты, выявленные в процессе
сбора требований. Среди возможностей веб-приложений COM следует
отметить хранение данных, связанных с выявленными объектами, чтение
данных об этих объектах,
Объектно-ориентированное (ОО) проектирование и анализ представляют собой большую редкость в современном сообществе разработчиков программного обеспечения. Веб-программы не менее сложны, чем другое комплексное программное обеспечение, имеют неопределенную структуру при разработке и дизайне, поэтому не следует игнорировать зарекомендовавшие себя правила и подходы к разработке.
В организациях проектирование и анализ зачастую выполняются после создания продукта, и в этом случае каждое усовершенствование требует его перестройки. В любом проекте время, отведенное для анализа и проектирования, влияет на завершение процесса программирования в намеченные сроки, позволяет в будущем без особых проблем усовершенствовать программу и усиливает командный дух специалистов, занятых разработкой.
Существует проблема, связанная с ОО-анализом и проектированием в VB6. VB6 не позволяет создать действительно объектно-ориентированное программное решение. Эта среда программирования не поддерживает наследование реализации. Отсутствие реального полиморфизма и других возможностей ограничивает его эффективность при разработке приложений, обеспечивающих долговечность, особенно для масштабируемого программного решения. Объекты COM можно построить на других ОО-языках, например, на C++ и Java.
VB6 поддерживает другие возможности истинно полиморфного языка, но
наследование классов – очень важная функция – в нем отсутствует. Не
следует воспринимать наследование в VB6 за истинное наследование.
Документация Microsoft описывает VB6 как объектно-ориентированный язык,
обеспечивающий наследование классов с помощью команды implements.
Однако команда implements обеспечивает только наследование интерфейса.
С практической точки зрения это означает, что IDE в VB6 заново
конструирует интерфейс суперкласса в
VB6 позволяет быстро разработать надежные компоненты, обеспечивающие функциональность, связанную с экземпляром класса. Классы используют другие классы, что весьма полезно. Вероятно, лучшей демонстрацией возможностей VB6 является проект, в котором на этапе сбора требований выявлено немного объектов, или проект с небольшим потенциалом для масштабируемости в будущем и с коротким циклом разработки. VB6 является альтернативой истинно полиморфного языка типа C++, требующего от программиста высокого уровня знаний, и технологии сценариев типа VBScript ASP.
Возьмем созданный ранее объект "стул" и используем его в дальнейшем
процессе разработки, т.е. усовершенствуем объект, добавив функции
чтения и записи данных в базу данных, упорядочивание состояния
экземпляра класса и его фиксирование в документе XML. В класс clsChair
добавятся следующие функции.
OpenChair(ID as string) as Boolean – открывает имеющуюся запись "стул"
и заполняет объект значениями.CreateChair() as Boolean – генерирует новый ID, заполняет объект новым
ID и записывает запись в базу данных.GetChairState() as XMLDOM – упорядочивает состояние объекта в XML DOM в
виде: <Chair ID="" Color="" />.В класс clsChair добавятся следующие свойства.
ChairID as String – Read Only. Идентификатор, используемый для
уникальной идентификации рассматриваемого объекта "стул".ChairError as String – Read Only. Описание последней обнаруженной
ошибки, имевшей место в классе clsChair.Интерфейс по-прежнему не сложен, однако теперь он более соответствует
классу в истинном объектно-ориентированном программном решении.
Целесообразно добавить в интерфейс и другие функции: delete (удаление)
и save (сохранение) – однако для сокращения приводимых в книге примеров
рассматривать их не будем.
Имя chair предшествует именам функций в классе clsChair. Создавать
интерфейс к объекту, использующий имя самого объекта, не рекомендуется,
однако этого требуют ограничения данной технологии. Оpen и create
являются ключевыми словами, зарезервированными в VB, поэтому их нельзя
использовать в качестве имен пользовательских функций в экземпляре
класса. Следует заметить, что наследование класса не содержит
какой-либо логики, за исключением того, что связано с описанием самого
стула или с его действиями в рассматриваемом сценарии. Отсутствует
логика данных или логика представления, например, строки подключения к
базе данных или HTML-вывод.
В листинге 1.3 приведен общий интерфейс объекта "стул"; он содержит объявления следующих функций, включая код реализации.
clsChair Prototypes Public Property Get color() As Variant End Property Public Property Let color(ByVal vNewValue As Variant) End Property Public Property Get ChairError() As String End Property Public Property Get ChairID() As String End Property Public Function OpenChair(ID As String) As Boolean End Function Public Function CreateChair() As Boolean End Function Public Function GetChairState() As DOMDocument30 End Function
Свойства в VB представляют собой обычные функции для упрощения доступа
и присвоения значений. Программист может включить в подпрограмму
свойства код, реализующий работу программы. Рекомендуется создавать
функции или подпрограммы для ситуаций, в которых работа выполняется
программой. Хорошим примером функции в классе clsChair, являющейся
свойством "только для чтения", будет GetChairState(). GetChairState()
выполняет работу по созданию кода XML, поэтому она размещена в функции,
возвращающей экземпляр класса. Если класс DOMDocument30 сохранен в
локальной переменной класса и инициирован после вызова функции Open()
или Create(), то использование свойства с доступом "только для чтения"
является лучшим способом возврата экземпляра класса DOMDocument30.
Поскольку свойства ChairError и ChairID доступны только для чтения, то
при попытке записи в функцию значения произойдет ошибка. Свойство color
является единственным свойством, поддерживающим чтение и запись,
поскольку существуют два прототипа свойства – Get и Let. Свойства ChairError и ChairID доступны только для чтения, поэтому содержат
только прототип Get.
Ни в одном фрагменте кода данной лекции не показана еще одна возможность
VB, которая, правда, не очень важна. Свойство может принимать и
возвращать аргумент экземпляра класса. Если для принятия экземпляра
класса используется прототип свойства, то используется ключевое слово Set, а не Let. Например, если класс clsChair имеет свойство записи ChairState, которое воспринимает экземпляр класса XML DOM как аргумент,
то прототип выглядит следующим образом:
Public Property Set ChairState(ByVal vNewValue As DOMDocument30) End Property
Общей проблемой VB-приложений является неправильная поддержка
абстракции логики. Если класс clsChair создан для чтения и записи
данных в источник типа базы данных, то программист может включить в
этот класс свойство Connection. Свойство Connection предоставляет
классу информацию, необходимую для подключения к базе данных. Такой
подход нежелателен, потому что возникают проблемы с расширяемостью
интернет-приложений, написанных на языке VB. Интерфейс класса не
отражает реальное положение дел, поскольку объект "стул" не имеет
атрибута Connection на самом деле. Размещая свойство Connection в
интерфейсе, программист предполагает, что потребителю класса известно,
каким образом класс взаимодействует с источником данных. Атрибут Connection и подобные технические атрибуты не должны вредить
интерфейсу. Здесь правильным решением является абстрагирование в
бизнес-логике от всего, что не относится к объекту в реальной жизни.
Как программист может обеспечить "чистоту" логической абстракции класса и реализовать подключение к базе данных? Ввод вручную информации о подключении в классе, разумеется, не выход из положения, так как требует изменения кода. Всякое программное обеспечение должно иметь параметры состояния, доступные при инициализации или конструировании. Для сервера Windows механизмом хранения данных состояния или инициализации является реестр, который используется всеми утилитами и службами поддержки Windows. Технология .NET унаследовала использование файлов XML для хранения данных о развертывании и состоянии интернет-приложений.
Любая система работает до тех пор, пока программному обеспечению
известен контекст хранения данных инициализации. Реестр Windows
отыскивается всегда одинаково, независимо от узла его расположения.
Программа не должна искать реестр на диске C:, ведь на другом сервере
он может располагаться в другом месте. Реестр обладает контекстом,
связанным с самим узлом, а не с положением файла на узле, внутри
сервера или внутри сервера на отдельном узле. В интернет-приложениях
корневой веб-каталог выступает в роли общего узла контекста. К
содержимому или файлам можно обращаться в контексте корневого
веб-каталога. Он может располагаться на диске C: или D:, и при
выражении контекста как корневого веб-каталога не возникнет проблем,
связанных с нахождением значения данного параметра инициализации.
Платформа .NET унаследовала стандарт хранения данных развертывания в
файлах XML с именем Web.config, которые располагаются в любом каталоге
структуры веб-каталогов. Более подробная информация о приложениях .NET
и использовании файла web.config приведена в лекциях 2 и 3.
Так как класс clsChair размещен в приложении COM+, то реализован
интерфейс IobjectConstruct для получения аутентификационных данных при
подключении к базе данных. Для его использования в список ссылок
проекта класса добавлена ссылка COM+
Интерфейс IObjectConstrucion реализован с использованием команды Implements, и в класс добавлена подпрограмма события IObjectConstruct_Construct. Эта подпрограмма выполняется при
инициализации класса и передает экземпляр объекта классу,
представляемому параметром pCtorObj. Экземпляр класса, на который
указывает pCtorObj, имеет свойство ConstructString. Значение ConstructString использовалось для инициализации объекта ADO Connection, повсеместно применяемого в классе clsChair. В листинге 1.4
показана подпрограмма события IObjectConstruct_Construct.
IObjectConstruct_Construct event subroutine implementation in clsClass
Option Explicit
Implements IObjectConstruct
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' ***** constants to class *****
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'old style connection string in case nothing else works
Private Const DEFAULT_CONSTRUCTION_STRING = _
"driver={Microsoft Access Driver (*.mdb)};" _
"dbq=D:\aspData\employees.mdb"
Private Const DEFAULT_COLOR = "Brown"
Private Const CHAIR_ID = "ID"
Private Const CHAIR_COLOR = "Color"
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' ***** locals to class *****
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'holds the color of the chair
Private m_scolor As String
'Chair ID for class instance
Private m_sID As String
'holds the ADO Connection to the data
'source that the object interacts with
Private m_Connection As ADODB.Connection
Private m_sErrorMessage As String
Private Sub IObjectConstruct_Construct(ByVal pCtorObj As Object)
On Error GoTo Sub_Error_Handler
Const ERROR_MESSAGE_INFO = "IObjectConstruct_Construct"
Dim sConnection As String
sConnection = pCtorObj.ConstructString
'make certain there is something
If Len(sConnection) < 1 Then
sConnection = DEFAULT_CONSTRUCTION_STRING
End If
'establish connection to database server
If m_Connection Is Nothing Then
Set m_Connection = CreateObject("ADODB.Connection")
End If
m_Connection.Open sConnection 'DEFAULT_CONSTRUCTION_STRING
'establish connection to database server
Set m_Connection = CreateObject("ADODB.Connection")
m_Connection.Open sConnection '"DSN=ASPExample"
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub_Exit_Done:
Exit Sub
Sub_Error_Handler:
'record the error in class instance and rethrow
'for consuming software to learn of issue
ProcessErr ERROR_MESSAGE_INFO _
" Failure obtaining database connection information." _
" Class will not connect to database"
End Sub
Значение свойства ConstructString устанавливается в окне свойств службы
компонентов. Для clsClass строка подключения задана в текстовом поле
Constructor String (Строка конструктора) вкладки Activation (Активация)
окна свойств компонента ConfigSeat.clsClass (см. рис. 1.18). При
использовании данного механизма хранения данных о состоянии
инициализации класс clsChair настраивается при помощи обычных служб
Windows Server, с которыми знаком любой инженер, обслуживающий такой
сервер.
Примечание. Технология доступа к данным Windows, использующая
m_Connection, является локальным по отношению к классу clsChair (см.
рис. 1.4). Это означает, что подключение открыто, пока существует
экземпляр класса clsChair. При уничтожении экземпляра класса clsChair
экземпляр подключения ADO уничтожается, однако провайдер ODBC или
OLE-DB сохраняет экземпляр подключения для следующего запроса. Не нужно
кэшировать объекты подключения или создавать ситуации, требующие
кэширования, поскольку Windows и так выполняет эту функцию.
(рис 1.18) Вкладка Activation (Активация) окна свойств ConfigSeat.clsClass
Взаимодействие с базой данных выводит нас на новый уровень сложности приложения, для которого требуется большая надежность в критических ситуациях. Корректная поддержка ошибок является необходимым условием реализации любого кода; она должна обрабатывать ситуации, которые вызывают возникновение ошибки в подпрограмме, например, при взаимодействии с пользователем или при соединении с разнородными системами.
В Visual Basic имеется система обработки ошибок, легкая в использовании и управлении. Отсутствие обработки ошибок распространяется и на программу-потребителя. В этом случае пользователь видит малоинформативное сообщение, и программа прерывает свою работу. В веб-приложении, где COM-объект используется страницей ASP, конечному пользователю отображается сообщение об ошибке, если IIS настроен на показ таких сообщений.
Каждая исключительная ситуация, имеющая место в классе clsChair,
фиксируется в журнале событий и сохраняется в локальной переменной
свойства ChairError. Код написан таким образом, что при получении
информации об ошибке приостанавливается его работа. Обработка ошибок в
классе clsChair реализована с использованием той же sub_Exit_Done и sub_Error_Handler. Строка sub_Error_Handler
представляет стратегию, согласно которой действия осуществляются при
возникновении исключительных условий, указанных в выражении On Error.
Код, следующий за строкой sub_Exit_Done, представляет собой обычную
стратегию выхода функции или подпрограммы, если при работе программы не
возникают исключительные ситуации. В листинге 1.5 приведена типовая
структура системы обработки ошибок, примененная в классе clsClass.
Error Handling Framework On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "This Function's name" Part of the function that actually does something here '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done: 'return success value On Error Resume Next 'destroy objects Exit Function Sub_Error_Handler: ProcessErr "message about the failure in terms of function"
Подпрограмма ProcessErr, вызываемая в рамках стратегии обработки
исключительных условий, обрабатывает ошибки VB или другие неверные
условия. ProcessErr выполняет следующие действия:
Журнала не будет заполняться до тех пор, пока компонент не будет скомпилирован, по причине ограничения VB и мер безопасности Windows. При выполнении компонента в VB IDE журналы событий не ведутся.
В листинге 1.6 приведен код подпрограммы ProcessErr.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'ProcessErr 'formats error and stores it in error local 'then write to event log. Event logging 'will not function in IDE - only in compiled. ' 'in: vsMessage - usually denoting function 'out: nothing '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Private Sub ProcessErr(ByVal vsMessage As String) Const ERROR_SEPARATOR = " -- " Const NOW_TIME_FORMAT = "yyyy mmm d hh:mm:ss" Const A_SPACE = " " Const ERROR_NUM = " Error #" Const ERROR_BY = " was generated by " Dim sDateTime As String 'get a time data stamp sDateTime = CStr(Format(Now, NOW_TIME_FORMAT)) _ ERROR_SEPARATOR 'construct the error entry vsMessage = sDateTime vsMessage 'add err object data to the error entry m_sErrorMessage = vsMessage ERROR_NUM Err.Number _ ERROR_BY Err.Source A_SPACE Err.Description vbCrLf 'write to event log App.LogEvent m_sErrorMessage, vbLogEventTypeError End Sub
ProcessErr записывает время и добавляет его к описанию ошибки. Свойства
класса VB Err конкатенируются в строку, которая станет частью сообщения
об ошибке, фиксируемого и сохраняемого в локальной переменной ошибки.
Реализация функций CreateChair и OpenChair требует взаимодействия с
базой данных. Функция CreateDir вставляет данные о новом объекте "стул"
в базу данных, в OpenChair заполняет состояние экземпляра класса
значениями, считанными из базы данных. Функция Createchair генерирует
для этого объекта идентификатор ID, создает команду SQL и записывает
новые значения в базу данных при помощи выражения SQL INSERT. В
листинге 1.7 приведен код функции CreateChair.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'CreateChair
'Generates a new ID, populates object with
'the new ID, writes record to DB
'
'in: nothing
'out: returns true on success and false otherwise
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Public Function CreateChair() As Boolean
On Error GoTo Sub_Error_Handler
Const ERROR_MESSAGE_INFO = "CreateChair"
Const COMMAND_PREFIX = "INSERT INTO tblChair" _
" ([ID], [Color]) VALUES ('"
Const COMMAND_CONJUNCTION = "', '"
Const COMMAND_SUFFIX = "')"
Dim sNewID As String
Dim sSQL As String
'get new ID
sNewID = CreateNewID
'build the insert statement
sSQL = COMMAND_PREFIX sNewID _
COMMAND_CONJUNCTION m_scolor COMMAND_SUFFIX
'perform database update
If Not ExecuteCommand(sSQL) Then
Err.Raise 1001, ERROR_MESSAGE_INFO, _
"Failure updating database table for Chair ID = " sNewID
End If
'set new ID to local setting
m_sID = sNewID
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub_Exit_Done:
'return success value
CreateChair = True
On Error Resume Next
'destroy objects
Exit Function
Sub_Error_Handler:
ProcessErr " Failure Creating Chair. ID = " sNewID
End Function
При вызове функции CreateNewID генерируется новый ID объекта "стул". CreateNewID вызывает функцию New(), форматирует значение в виде
уникального числа и преобразует его в строку. В листинге 1.8 приведен
исходный код функции CreateNewID. Данный алгоритм имеет большой
недостаток. Он генерирует уникальную строку ID только в том случае,
если запрос выполняется через 1 с после предыдущего запроса ID. Для
получения уникальных значений необходимы более приемлемые подходы,
например, использование функции глобально уникального идентификатора
Windows (GUID) или других самодельных функций с генератором случайных
чисел. Этот недостаток не был устранен, чтобы класс clsChair стабильно
генерировал ошибку при записи информации в базу данных. Ошибка
возникает из-за того, что ID объекта "стул" является главным ключом в
таблице базы данных, в которой находится информация об этом объекте.
Запись строки, содержащей такое же значение ID, что и записанное ранее,
приведет к ошибке обновления ADO.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'CreateNewID 'creates a new ID for a new chair ' 'in: nothing 'out: returns string ID for Chair '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Private Function CreateNewID() As String Const NOW_TIME_FORMAT = "yyyymmddhhmmss" Dim sDateTime As String 'get a time data stamp sDateTime = CStr(Format(Now, NOW_TIME_FORMAT)) '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'Note: This algorithm has a huge flaw. 'It does not create unique IDs if more than 'one is requested in a given second. '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'return value CreateNewID = sDateTime End Function
После генерации ID конструируется выражение SQL с использованием
констант, являющихся частью выражения обновления SQL, с помощью
которого новые данные записываются в базу данных. Использованное
значение color в действительности является локальным значением m_scolor. Свойство color, как и me.color, можно (и нужно) использовать
вместо локального значения m_scolor. Если свойство color нужно
подтвердить или изменить из его текущего состояния в экземпляре класса,
то оно пригодится для внесения небольшого изменения в код в
единственном месте, однако в этом случае потребуется изменить код и в
свойстве, и в функции при помощи переменной m_scolor.
После построения команды SQL функция ExecuteCommand передает эту
команду в базу данных для выполнения (см. листинг 1.9). В этой функции
не предусмотрен возврат значения от события. При выполнении операции ExecuteCommand использует ADO.
Для работы с технологией ADO в набор ссылок проекта ConfigSeat нужно
добавить ссылку на ADO. ADO инсталлируется при помощи пакета Microsoft
Data Access Components (
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'ExecuteCommand
'sends a SQL command text to the datasource
'without expectation of return value
'
'in: vsSource - SQL string to execute
'out: returns true on success, false otherwise
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Private Function ExecuteCommand(ByVal vsSource As String) _
As Boolean
On Error GoTo Sub_Error_Handler
Const ERROR_MESSAGE_INFO = "ExecuteCommand"
Dim cmdRequested As ADODB.Command
'establish connection
If m_Connection.State <> adStateOpen Then
Err.Raise 1001, ERROR_MESSAGE_INFO, _
"Connection Object is not open. Database connect be opened."
End If
'establish command
Set cmdRequested = CreateObject("ADODB.Command")
Set cmdRequested.ActiveConnection = m_Connection
'set up command object
cmdRequested.CommandType = adCmdText
cmdRequested.CommandText = vsSource
'run SQL
cmdRequested.Execute
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub_Exit_Done:
'return success value
ExecuteCommand = True
On Error Resume Next
'destroy objects
Set cmdRequested = Nothing
Exit Function
Sub_Error_Handler:
ProcessErr " Failure executing SQL command."
End Function
В большей части вызовов Err.Raise, выполняемых при возникновении
исключительных ситуаций, выводится номер ошибки 1001. Можно указать
любой номер, однако это число выбрано для простоты. Используйте числа
из диапазона 1000 – 65535, предназначенного для нумерации особых
ошибок. Объект ADO Command предназначен для вызова сервера базы данных.
Если от объекта Command ожидается набор записей Recordset, то функция Execute возвращает набор записей ADO Recordset. Так как объект ExecuteCommand изначально не предназначен для возврата набора записей Recordset, объект Recordset, возвращаемый от объекта Command,
игнорируется.
ExecuteCommand проверяет, что локальный объект подключения m_Connection
установлен и жизнеспособен. После этого создается объект Command и
настраивается на отправку серверу команды SQL. Если во время выполнения ExecuteCommand возникнет ошибка, обработчик ошибок зафиксирует ее и
выйдет из функции, возвратив значение "ложь". Все переменные типа boolean в VB имеют значение "ложь", если им не присвоены иные значения,
поэтому включите в программу код, присваивающий функции значение
"истина" по достижении успеха.
Функция OpenChair открывает набора записей ADO Recordset по известному
ID объекта "стул", переданного функции, и заполняет экземпляр класса по
результатам перемещения к первой записи набора Recordset. В листинге
1.10 приведен исходный код функции OpenChair. Так как ID объекта
"стул" является уникальным в базе данных, то ввиду ограничений работы с
данными безопаснее считать, что функция возвращает только одну строку
данных, и, как правило, следует использовать именно первую строку. Recordset исследуется на наличие данных с помощью проверки MoveFirst в пустом
наборе Recordset приведет к ошибке. Свойства EOF или Recordset в одном из
направлений при помощи команд MoveNext или MovePrevious.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'OpenChair 'Opens an existing record for a chair and 'populates the object with the values ' 'in: Chair ID to open 'out: returns true on success and false otherwise '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public Function OpenChair(ID As String) As Boolean On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "OpenChair" Const COMMAND_PREFIX = "SELECT * FROM tblChair WHERE ([ID]='" Const COMMAND_SUFFIX = "')" Dim sSQL As String Dim rs As ADODB.Recordset 'build the insert statement sSQL = COMMAND_PREFIX ID COMMAND_SUFFIX 'get Recordset Set rs = GetADORecordSet(sSQL) 'make certain we got a valid Recordset If rs Is Nothing Then Err.Raise 1001, ERROR_MESSAGE_INFO, _ "Failure Opening Chair ID = " ID End If 'make certain that we got a Recordset 'with at least 1 value If rs.EOF And rs.BOF Then Err.Raise 1001, ERROR_MESSAGE_INFO, _ "Failure - record for Chair does not exist. ID = " ID End If rs.MoveFirst 'set new ID to local setting m_sID = rs(CHAIR_ID) 'set new color to local setting color = rs(CHAIR_COLOR) '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done: 'return success value OpenChair = True On Error Resume Next 'destroy objects Set rs = Nothing Exit Function Sub_Error_Handler: ProcessErr "Failure Opening Chair ID = " ID End Function
Набор Recordset, полученный для OpenChair, создан другой
вспомогательной ADO-функцией – GetADORecordSet. Как и ExecuteCommand, GetADORecordSet воспринимает выражение SQL как параметр и открывает
набор Recordset из источников данных в локальном экземпляре m_Connection объекта Connection. Объект набора записей передается в
вызывающую функцию. В листинге 1.11 приведен исходный код функции GetADORecordSet.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'GetADORecordSet
'Sends SQL command to datasource and returns
'an ADO Recordset to the function consumer
'
'in: vsSource - SQL string to execute
'out: returns true on success, false otherwise
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Private Function GetADORecordSet(ByVal vsSource As String) _
As ADODB.Recordset
On Error GoTo Sub_Error_Handler
Const ERROR_MESSAGE_INFO = "GetADORecordSet"
Dim rsRequested As ADODB.Recordset
Dim cmdRequested As ADODB.Command
'establish connection
If m_Connection.State <> adStateOpen Then
Err.Raise 1001, ERROR_MESSAGE_INFO, _
"Connection Object is not open. Database connect be opened."
End If
'establish command
Set cmdRequested = CreateObject("ADODB.Command")
Set cmdRequested.ActiveConnection = m_Connection
'set up command object
cmdRequested.CommandType = adCmdText
cmdRequested.CommandText = vsSource
'Create instance of Recordset object
Set rsRequested = cmdRequested.Execute
'return Recordset
If Not rsRequested Is Nothing Then
If rsRequested.State = adStateOpen Then
Set GetADORecordSet = rsRequested
Else
'rsRequested state is not open
Err.Raise 1001, ERROR_MESSAGE_INFO, _
" Recordset state is not open " vsSource
End If
Else
'rsRequested is nothing error
Err.Raise 1001, ERROR_MESSAGE_INFO, _
" Recordset object is nothing " vsSource
End If
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub_Exit_Done:
'return value
On Error Resume Next
'destroy objects
Set rsRequested = Nothing
Set cmdRequested = Nothing
Exit Function
Sub_Error_Handler:
ProcessErr " Failure obtaining Recordset."
End Function
Существует много возможностей по усовершенствованию функции GetADORecordSet. Одной из них является установка набора ADO Recordset
как параметра функции, передаваемого в ByRef, и возврат значения
"истина" или "ложь" в зависимости от результата извлечения набора Recordset. Программа расходует ресурсы на создание набора записей ADO Recordset только один раз, и функция сообщит вызывающей функции о
правильности набора Recordset. Функции ExecuteCommand и GetADORecordSet
можно объединить в одну.
Функция GetChairState создает документ XML, описывающий экземпляр
класса clsChair. XML является простым одноэлементным документом.
Элемент Chair содержит два атрибута: ID и Color. Для использования
объекта XML добавьте в проект ссылку на библиотеку MSXML (см. рис.
1.7). В нашем проекте выбрана библиотека Microsoft XML v3.0, но
существуют и другие версии этой библиотеки. На момент публикации книги
уже вышла четвертая версия. В подпрограмме применяется конкатенация
строк для построения XML и возврата строки из класса. Однако такой
подход опасен, поскольку в большинстве XML-анализаторов сразу возникнет
ошибка при некорректности любой части XML. Создание XML с
использованием анализатора позволит правильно построить XML. В листинге
1.12 приведен исходный код функции GetChairState.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' ChairID - read only '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public Property Get ChairID() As String ChairID = Trim(m_sID) End Property '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'GetChairState 'serializes object state into XML DOM 'to look like this <Chair ID="" Color="" /> ' 'in: nothing 'out: returns DOMDocument30 object filled '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public Function GetChairState() As DOMDocument30 On Error GoTo Sub_Error_Handler Const ERROR_MESSAGE_INFO = "GetChairState" Const CHAIR_ELEMENT = "Chair" Const CHAIR_ID_ATTRIBUTE = "ID" Const CHAIR_COLOR_ATTRIBUTE = "Color" Dim xmlChair As MSXML2.DOMDocument30 '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'note : Constructing the XML using 'string concatenation and using the 'XML object to validate is another 'strategy often times used. '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'refresh the object OpenChair Me.ChairID 'build XML document Set xmlChair = New DOMDocument30 'create the element for Chair Set xmlChair.documentElement = _ xmlChair.createElement(CHAIR_ELEMENT) 'add the Chair attributes xmlChair.documentElement.setAttribute _ (CHAIR_ID_ATTRIBUTE), ChairID xmlChair.documentElement.setAttribute (CHAIR_COLOR_ATTRIBUTE), color '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub_Exit_Done: 'return object Set GetChairState = xmlChair On Error Resume Next 'destroy objects Set xmlChair = Nothing Exit Function Sub_Error_Handler: ProcessErr " Failure serializing chair into XML. " End Function
После изучения кода в листинге 1.12 становится ясно, почему при
построении XML используется конкатенация строк. Применение DOM Document
интуитивно непонятно, и кажется, что для построения форматированной
строки выполняется очень большой объем работы. Первая версия библиотеки
XML MSXML.DLL была медленной и неэкономичной с точки зрения ресурсов;
здравомыслящий программист реализует XML гораздо быстрее конкатенацией
строк. Язык VB не достаточно эффективен для этого. Сокращение
изменений, вносимых в строку, кардинально улучшает производительность.
Поскольку технологии, связанные с XML, являются довольно новыми,
программное обеспечение, поддерживающее эти технологии, должным образом
не "устоялось". Программист должен быть в курсе новых данных от
производителя и авторов статей и книг, так как данная технология
постоянно модернизируется.
Новый класс clsChair можно протестировать после расширения тестовой
структуры (см. рис. 1.8) для проверки созданного интерфейса. В
тестовую структуру были добавлены кнопки Get XML (Получить XML), Open
(Открыть) для открытия нового экземпляра объекта "стул" и Create
(Создать) (см. рис. 1.19). Перед нажатием на кнопку Open (Открыть)
укажите в текстовом поле аргумент стула ID.
(рис 1.19) Расширенная тестовая структура для clsChair
Если при перекомпиляции ConfigSeat.dll не скомпилирована тестовая
структура, то может возникнуть ошибка при создании экземпляра класса.
Это возможно для любого COM-объекта, если другая программа использует
COM-объект и содержит ссылки на него. В VB проект ActiveX DLL
настраивается на совместимость с проектом по умолчанию во вкладке
Component (Компонент) окна свойств проекта. При перекомпиляции
рассматриваемого проекта ActiveX DLL не будет установлена совместимость
с двоичными файлами, поэтому при выполнении других программ со
скомпилированными ссылками на библиотеку ActiveX DLL возникнут ошибки.
Для иллюстрации вышесказанного рассмотрим следующую ситуацию: ConfigSeat.dll скомпилирована в 9:00 утра. В полдень скомпилирована
тестовая структура с именем testconfigseat.exe. Тестовая структура testconfigseat.exe содержит определенные ссылки на ConfigSeat.dll, и в
ее коде класс озаглавлен строго определенным образом. В 18:00 проект ConfigSeat.dll перекомпилирован и установлена совместимость с проектом.
При выполнении в 18:08 файл testconfigseat.exe вызвал ошибку, поскольку
не смог найти библиотеку ConfigSeat.dll из-за изменения CLSID. При
каждой компиляции ConfigSeat без указания совместимости с двоичными
файлами генерируется новый CLSID. После настройки компонента на
совместимость с двоичными файлами (см. рис. 1.20) VB использует один и
тот же CLSID при каждой компиляции DLL, поэтому любое зависимое от
библиотеки программное обеспечение работает исправно.
Приложение, использующее библиотеку ActiveX DLL, ожидает интерфейс для данного CLSID. Изменение интерфейса класса иначе, чем добавлением новой функции или свойства, вызовет ошибки в приложениях-потребителях, работа которых основывается на классе.
(рис 1.20) Во вкладке Component (Компонент) окна свойств проекта установлена совместимость с двоичными файламиВы можете добавить новые функции, однако нельзя изменить или удалить имеющиеся параметры. Для имени библиотеки и класса идентификатор CLSID остается неизменным, что достигается компиляцией, совместимой с двоичными файлами. Преимуществом совместимости с проектами является то, что программист может ссылаться на проект ActiveX DLL и легко изменять интерфейсы внутренних классов. Поскольку при программировании интерфейс меняется, совместимость с проектами позволит VB разрешить изменения, не предупреждая о нарушении совместимости при удалении или редактировании общей функции.
ConfigSeat.dll можно скопировать в среду сервера и разместить в
приложении COM+, заменив предыдущую версию ConfigSeat.dll. Приложение
COM+ в службах компонентов может заблокировать DLL. После отключения
приложение в службах компонентов библиотека DLL освобождается для
удаления. Если библиотека DLL участвует в работе веб-приложения, то
веб-сервер не будет использовать класс clsChair после удаления классов
в DLL из приложения COM+.
Сейчас мы выполним загрузку новой версии clsClass в приложение COM+ New
ConfigSeatWeb.
ConfigSeat.clsClass, щелкнув правой кнопкой мыши на компоненте и выбрав
Delete (Удалить).ConfogSeat.clsClass.IObjectConstruct_Construct, приведенной в листинге 1.4. В классе ConfigSeat.clsClass строка конструктора содержит строку подключения ADO
для получения доступа к информации в базе данных (см. рис. 1.18).clsChair загружен, выполнив на нем быстрый
модельный тест. Тестовая структура проясняет функциональность класса
внутри новой среды. Исполняемый файл скопируйте на узел и запустите.
Выполните более простой тест с помощью DescribeChair.asp (см. листинг
1.2), добавив несколько новых вызовов функций для нагрузки компонента.
В листинге 1.13 приведена расширенная версия файла DescribeChair.asp с
именем DescribeChairFinal.asp.<%@ Language=VBScript %>
<HTML>
<HEAD>
</HEAD>
<BODY>
<%
dim i
dim o
dim oXML
Response.Write("<p>start Test</p>")
'create the object since this is hard work
set o = Server.CreateObject("ConfigSeat.clsChair")
'demonstrate that values were changing
Response.Write("<p> color=" o.color "</p>")
Response.Write("<p>change color to blue</p>")
o.color = "blue"
Response.Write("<p> color=" o.color "</p>")
if o.CreateChair() then
Response.Write("<p> new id=" o.ChairID "</p>")
else
Response.Write("<p> possible error=" o.ChairError "</p>")
end if
set oXML = o.GetChairState()
Response.Write("<p> xml=" oXML.XML "</p>")
Response.Write("<p> open new chair</p>")
if not o.OpenChair("20021129095221") then
Response.Write("<p> possible error=" o.ChairError "</p>")
end if
Response.Write("<p> new chair color should be purple</p>")
Response.Write("<p> new chair color =" o.color "</p>")
'destroy object so it can be created again
set o = nothing
%>
</BODY>
</HTML>
Запустите тест нагрузкой из утилиты Microsoft Application Center Test,
и вы увидите, что работа приложения ASP – COM – база данных требует
больше ресурсов, чем простое приложение ASP – COM. Предыдущая версия clsChair не предусматривает взаимодействия с базой данных, и база
данных располагается на том же сервере, где расположены ASP и
COM-объект clsChair. При моделировании одновременной работы 100
пользователей в течении 5 минут выяснилось, что приложение способно
поддерживать среднюю нагрузку, равную 45 запросам на страницы в
секунду.
На рисунке 1.17 показано окно служб компонентов, отображающее
состояние предыдущего теста. В тесте для предыдущей версии clsChair
заголовки Call и не регистрировали никаких значений, кроме 0.
В последней версии clsChair поле In Call стабильно отображало значения
от 0 до 1, а поле стало равным 15 мс. Очевидно, что
производительность компонента заметно снизилась по сравнению с
проведенным ранее тестом. Как видите, дополнительная функциональная
нагрузка, связанная со считыванием информации из базы данных, снижает
эффективность работы веб-приложения.
Класс clsChair поддерживает обобщение логики представления. Функция GetChairState создает упорядоченную версию объекта "стул" потребителю,
осуществляющему построение страницы. Как правило, веб-приложения COM
используют ASP-страницу для анализа представления HTML, реализации
классов и упрощения прорисовки страницы посредством связывания
XML-объектов с документами XML, необходимыми для построения страницы. В
ситуации COM – ASP – XSL (или XSLT) можно создать многозвенное
приложение, обобщающее типы логики и технологии, приведенные в таблице
1.1.
| Название звена | Поддерживаемая технология |
|---|---|
| Логика представления | Лист XSL или XSLT |
| Бизнес-логика | VB COM и ASP. |
| Логика доступа к данным | ADO |
| Логика данных | SQL Server |
Страница ASP является уникальной частью программного решения, поскольку
объединяет бизнес-логику и логику представления. В программном решении,
представленном выше, ASP не была чистым обобщением бизнес-звена или
звена представления, поскольку содержала аспекты каждого из них. В
листинге 1.14 приведен исходный код страницы-диспетчера ASP,
использовавшейся с clsChair. XMLCOMChair.asp не содержит кода HTML, вся
страница отображается на листе XSL. Независимо от способа отображения
данных из clsChair в браузере, ASP не требует внесения изменений. ASP
должна иметь сведения об интерфейсе класса clsChair, поэтому в код
включена бизнес-логика. Если в класс clsChair добавляются новые функции
или свойства, то нужно отредактировать код ASP. ASP легко
параметризуется в соответствии с настраиваемой системой запуска
классов, полностью абстрагируясь от бизнес-логики и логики
представления.
<%@ Language=VBScript %>
<%
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
' Drawpage
' handles XML transformation
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub Drawpage(sXML)
CONST XSL_FILE = "formatChair.xsl"
dim oXML
dim oXMLXSL
Set oXMLXSL = Server.CreateObject("Microsoft.XMLDOM")
Set oXML = Server.CreateObject("Microsoft.XMLDOM")
'load XML
oXML.loadXML(sXML)
'load the XSL
oXMLXSL.load(Server.MapPath(XSL_FILE))
'write the page
Response.Write(oXML.transformNode(oXMLXSL))
'destroy object
set oXML = nothing
set oXMLXSL = nothing
end sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
' main
' dispatches calls
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
sub Main()
dim o
dim XMLDOM
'create the object chair
set o = Server.CreateObject("ConfigSeat.clsChair")
'check for color setting
if len(Request("color"))>0 then
o.color = Request("color")
end if
'decide what to do
select case Request("Action")
case "New"
o.CreateChair
case "Open"
o.OpenChair Request("ID")
end select
'get the object state
set XMLDOM = o.GetChairState()
'write the page
Drawpage XMLDOM.XML
'destroy object
set o = nothing
set XMLDOM = nothing
end sub
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
' Script entry point
'~~~~~~~~~~~~~~~~~~~~~~~~~~~
Main()
%>
После выполнения экземпляром класса clsChair своей бизнес-логики
состояние clsClass преобразуется в XML и используется для построения
страницы HTML. Имя листа XSL – formatChair.xsl – хранится в коде ASP,
но его можно получить другим способом, например, с помощью аргументов
HTTP в представлениях форм или ссылках. Подпрограмма Drawpage при
помощи строкового аргумента, содержащего XML, прорисовывает конечную
веб-страницу. Лист XSL определяет способ построения веб-страницы и
отображение значений в XML. В XSL можно расположить и другие данные,
например, сценарии JavaScript, предназначенные для выполнения в
браузере. В листинге 1.15 приведен код листа XSL formatChair.xsl.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <xsl:template match="/"> <xsl:comment> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ XSL Sheet primarily for the purposes of building an HTML page to allow a user to open or create a new chair and see the results with the presentation logic abstracted completely ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ </xsl:comment> <xsl:comment> Start the HTML page here </xsl:comment> <HTML> <HEAD> <TITLE>XML COM page</TITLE> </HEAD> <BODY> <xsl:comment> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ build table for chair data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ </xsl:comment> <xsl:for-each select="Chair"> <P>current</P> <TABLE BORDER="1" CELLSPACING="0" CELLPADDING="0"> <TR> <TH>ID</TH> <TH>Color</TH> </TR> <TR> <TD><xsl:value-of select="@ID"/></TD> <TD><xsl:value-of select="@Color"/></TD> </TR> </TABLE> </xsl:for-each> <xsl:comment> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ XSL parts are completed Please never forget, all HTML must be well formed also. XSL is also case sensitive. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ </xsl:comment> <P>command </P> <xsl:comment> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ build table for commanding new chair data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ </xsl:comment> <FORM METHOD = "POST" ACTION = "XMLCOMChair.asp" ID = "frmImage" NAME = "getInfo" > <TABLE BORDER="1" CELLSPACING="0" CELLPADDING="0"> <TR> <TD>Action</TD> <TD> <input TYPE="text" NAME="Action" VALUE="Open or New"> </input> </TD> </TR> <TR> <TD>ID</TD> <TD><input TYPE="text" NAME="ID" VALUE=""></input></TD> </TR> <TR> <TD>color</TD> <TD> <input TYPE="text" NAME="color" VALUE="puce"> </input> </TD> </TR> </TABLE> <input ID="subFull" NAME="subR" TYPE="submit" VALUE="Go"></input> </FORM> </BODY> </HTML> </xsl:template> </xsl:stylesheet>
При XSL-программировании следует иметь в виду несколько важных моментов. Любой файл XSL должен быть правильно сформирован, т.е. соответствовать стандартам XML, принятым Консорциумом WWW (W3C). Ошибки в формировании файлов, как правило, вызываются следующими проблемами в коде XML.
Редакторы XML позволяют обнаружить больше ошибок при формировании XML. Пользуйтесь редактором XML для упрощения диагностики ошибок в программном решении, использующем XML, или для разработки программного обеспечения, реализующего построение XML. При неправильном формировании документа XML никакая конструкция, требующая этот документ, работать не будет. Существующие на сегодняшний день анализаторы XML не дают подробной информации о причине ошибки, поэтому поиск проблемы может оказаться затруднительным.
Когда программное решение целиком отгружено на сервер, и браузер
запрашивает XMLCOMChair.asp, то отображаемая страница должна иметь
следующий вид (см. рис. 1.21).
(рис 1.21) XMLCOMChair.asp использует clsChair и formatChair.xsl для
прорисовки веб-страницы
В XML для описания данных используется обычный текст, поэтому возможны
проблемы, связанные с расшифровкой данных из структуры XML. Возьмем, к
примеру, имя сотрудника компании O'Brien. Что произойдет, если
программа поместит список сотрудников, в который входит и O'Brien, в
документ XML, предназначенный для отображения в браузере? Элемент XML
будет выглядеть так: <имя сотрудника="O'Brien">. Если апостроф не будет
закодирован как специальный символ, то в анализаторе XML при загрузке
кода произойдет ошибка. При кодировании специальных символов
соответствующим образом элемент XML примет вид: <имя
сотрудника="Oapos;Brien">.
Многие символы требуют кодирования. Специальные символы представляются в виде числовых ссылок из набора символов ISO/IEC 10646. Некоторым символам присвоены специальные знаковые последовательности, вид которых соответствует обозначаемому символу.
| Символ | Последовательность знаков общей сущности |
|---|---|
| amp; | |
| < | lt; |
| > | gt; |
| ' | apos; |
| " | quot; |
Например, числовая ссылка на символ "" имеет вид "#38;", можно использовать и представление "amp;". Числовым представлением символа "=" является "#61;". Для данного символа отсутствует знаковая последовательность. Для получения информации о других символах и эквивалентных им представлениях обратитесь к Приложению. Дополнительная информация по XML приведена на странице http://www.w3.org/TR/REC-xml, где можно ознакомиться с W3C-спецификацией для XML.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.