Лабораторная работа 1 Данный документ является описанием лабораторной работы 1 к курсу «Технологии программирования. Ком...
1 downloads
169 Views
457KB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Лабораторная работа 1 Данный документ является описанием лабораторной работы 1 к курсу «Технологии программирования. Компонентный подход». Задача этой лабораторной работы — разработка Web-приложения на основе технологии ASP.NET и среды интеграции NHibernate. В рамках работы предлагается создать Web-приложение для просмотра и редактирования небольшой библиотечной базы данных (БД).
Содержание Необходимое программное обеспечение, оборудование и материалы................................1 План работы ...............................................................................................................................2 Ознакомление с требованиями к приложению.......................................................................3 Определение архитектуры приложения ..................................................................................3 Проектирование и создание БД приложения..........................................................................4 Разработка компонентов модели данных приложения..........................................................4 Определение архитектуры пользовательского интерфейса приложения ............................5 Проектирование отдельных форм приложения......................................................................5 Разработка отдельных форм приложения и их интеграция ..................................................5 Приложение 1. Пример требований к разрабатываемому приложению и примеры вопросов по требованиям. ........................................................................................................6 Требования к создаваемому приложению ..........................................................................7 Приложение 2. Примеры определения архитектуры приложения. ......................................8 Приложение 3. Пример схемы БД приложения и SQL-скриптов для ее создания. ............9 Приложение 4. Пример кода компонентов модели данных приложения и описания их отображения на БД. .................................................................................................................13 Приложение 5. Пример архитектуры пользовательского интерфейса приложения.........18 Приложение 6. Пример проекта форм приложения.............................................................19 Форма просмотра информации о книгах ..........................................................................19 Форма аутентификации привилегированных пользователей .........................................20 Форма редактирования информации о книгах .................................................................21 Приложение 7. Пример конфигурационных файлов и кода форм приложения. ..............22 Расположение файлов приложения и конфигурационные файлы..................................22 Основная форма приложения.............................................................................................24 Форма аутентификации ......................................................................................................31 Приложение 8. Примеры модульных и системных тестов для приложения.....................34 Модульные тесты. Основная форма приложения и навигация с нее .............................34 Модульные тесты. Форма аутентификации и навигация с нее.......................................35 Модульные тесты. Форма редактирования данных о книгах и навигация с нее ..........35 Системные тесты .................................................................................................................36
Необходимое программное обеспечение, оборудование и материалы Для выполнения данной лабораторной работы необходимо следующее программное обеспечение. 1. Microsoft Visual Studio.NET версии 1.1 (2003) или выше. 2. Microsoft Internet Information Services версии 5.0 или выше. Входит в состав серверных и профессиональных версий Microsoft Windows 2000, Microsoft Windows XP и Microsoft Windows 2003. 1
Должна быть установлена поддержка технологии ASP.NET 1.1 или выше. Эту поддержку можно определить при установке Microsoft Visual Studio. 3. NHibernate версии 1.0 или выше. Распространяется свободно, доступен, например, на сайте http://www.hibernate.org/30.html. 4. Одна из широко используемых СУБД. Возможны следующие варианты. a. Microsoft SQL Server 2000 и выше. Входит в состав профессиональных версий Microsoft Visual Studio или распространяется отдельно. b. Oracle версии 9.0 или выше. Версия Personal Edition распространяется свободно, например, доступна на сайте http://www.oracle.com/database/Personal_Edition.html. c. MySQL версии 4.0 или выше. Распространяется свободно. Доступно, например, на сайте http://dev.mysql.com/downloads/mysql/5.0.html. 5. Специализированное ПО для обеспечения связи СУБД со средой .NET —.NET Data Provider для выбранной СУБД. Возможны следующие варианты. a. Для SQL Server такое ПО входит в состав библиотек Visual Studio. b. Для Oracle такое ПО входит в состав библиотек Visual Studio. c. Для MySQL в дополнение к уже имеющейся в составе NHibernate библиотеке необходим только Connector/.Net, который свободно доступен на сайте http://dev.mysql.com/downloads/connector/net/1.0.html. Каждый компьютер, используемый в работе, должен совмещать роли компьютера для разработки и сервера приложений, поскольку в этом случае гораздо удобнее отлаживать отдельные элементы приложения. Такой компьютер должен иметь следующее. 1. Процессор Pentium 4 1 ГГц или более мощный; 2. Оперативную памятью 512 МБ или больше; 3. Установленную ОС Microsoft Windows 2000 Server, или Microsoft Windows XP Server, или Microsoft Windows 2003 Server; 4. Установленное перечисленное выше ПО. При выполнении заданий студенты должны иметь доступ к следующей документации. •
К общим руководствам по ASP.NET (например, Р. Андерсон, Б. Френсис, А. Хомер, Р. Хоуорд, Д. Сассмэн, К. Уотсон «ASP.NET для профессионалов», М.: Лори, 2004).
•
К документации MSDN на рабочем компьютере и/или в Интернет.
•
К документации по NHibernate (распространяется вместе с самой средой NHibernate).
•
К документации по ПО связи СУБД и .NET (для СУБД Oracle и SQL Server эта документация входит в состав MSDN, а для MySQL распространяется вместе с ПО Connector/.Net).
План работы Список шагов выполнения работы приведен ниже. Содержание шагов определено в соответствующих разделах данного документа. 1. Ознакомление с требованиями к приложению. 2. Определение архитектуры приложения. 2
3. Проектирование и создание базы данных приложения. 4. Разработка компонентов модели данных приложения. 5. Определение архитектуры пользовательского интерфейса приложения. 6. Проектирование отдельных форм приложения. 7. Разработка отдельных форм и интеграция приложения. Перечисленные шаги могут выполняться и в другой последовательности. Схема зависимостей между отдельными шагами изображена на Рис. 1. Шаги, не зависящие друг от друга можно выполнять в произвольном порядке и поручать их различным студентам, не организовывая специальным образом взаимодействие между ними. 1. Ознакомление с требованиями к приложению
2. Определение архитектуры приложения
3. Проектирование и создание БД приложения
5. Определение архитектуры пользовательского интерфейса
4. Разработка компонентов модели данных приложения
6. Проектирование отдельных форм приложения
7. Разработка отдельных форм и интеграция приложения Рисунок 1. Схема зависимости шагов выполнения лабораторной работы.
Ознакомление с требованиями к приложению В рамках данного шага студенты должны ознакомится с требованиями к разрабатываемому приложению и прояснить для себя все вопросы, связанные с его функциями. При ознакомлении с требованиями студенты изучают приводимые в Приложении 1 требования и разрешают все возникающие недоумения при помощи обсуждения, а также ответов преподавателя на четко сформулированные вопросы. Описание требований выдается каждому участвующему в работе студенту в таком виде, чтобы он мог делать на нем индивидуальные пометки. Например, так, как оно оформлено в Приложении 1. По окончании данного шага студенты должны уметь давать четкие ответы на все вопросы, касающиеся требований к приложению. Примеры вопросов по требованиям также даны в Приложении 1.
Определение архитектуры приложения В рамках этого шага должна быть определена общая архитектура приложения. Архитектура определяется на основании требований в виде набора компонентов, которые, 3
взаимодействуя друг с другом, обеспечивают реализацию всех функций приложения и выполнение нефункциональных требований к нему. Основные элементы этой архитектуры прямо указаны в требованиях. Студенты при определении архитектуры должны явно определить ее основные компоненты и связи между ними. Если лабораторная работа выполняется группой студентов, на этом этапе определяется распределение работ между ними. Рекомендуется поручать одну работу двум студентам с разделением ролей («программист» и «разработчик тестов и документации») для выработки навыков эффективного общения во время разработки. По окончании данного шага должна быть определена архитектура разрабатываемого приложения — набор основных компонентов, возможные связи и способы взаимодействия между компонентами, интерфейсы компонентов, возможные методы реализации компонентов или использование уже существующих. Дополнительно должна быть определена схема обеспечения защиты приложения. Варианты архитектуры приложения, интерфейсов его основных компонентов и схемы обеспечения защиты представлены в Приложении 2.
Проектирование и создание БД приложения В рамках этого шага на основе сформулированных требований проектируется и создается БД приложения. Созданная БД наполняется тестовыми данными, необходимыми для проверки работоспособности как самой базы, так и приложения в целом. В результате этого шага должна быть полностью определена схема БД приложения — набор таблиц, их полей, типы полей, связи между таблицами, первичные ключи и альтернативные ключи таблиц. БД приложения, соответствующая этой схеме, должна быть создана в рамках используемой СУБД. Кроме того, она должна быть наполнена тестовыми данными. Варианты схемы БД приложения приведены в Приложении 3.
Разработка компонентов модели данных приложения На этом шаге разрабатываются компоненты модели данных приложения, используемые как внутреннее представление его данных, хранимых в БД. Кроме того, определяется связь модели данных приложения с базой данных. Такая связь должна обеспечивать синхронизацию данных объектов приложения и таблиц БД, поддержку транзакций при работе с объектами и пр. В рамках среды интеграции NHibernate все эти функции реализуются автоматически, если задано отображение классов хранимых сущностей на таблицы и поля БД приложения. Компоненты модели данных приложения, построенного на основе NHibernate, представляют собой классы объектов, являющихся основными хранимыми сущностями приложения. В данном случае такими сущностями являются книги, авторы, издательства и привилегированные пользователи. При использовании NHibernate поля данных хранимых объектов должны быть определены как свойства соответствующих классов .NET, а поля таблиц, хранящие ссылки между ними, должны быть преобразованы в свойства-ссылки на соответствующие объекты или их коллекции. В результате выполнения этого шага должен быть написан код классов модели данных приложения, представляющих данные о книгах, авторах и издательствах, на языке C#.
4
Кроме того, должен быть написан конфигурационный файл NHibernate, определяющий отображение таблиц и полей БД приложения на классы модели данных и их свойства. Разрабатываемый на этом шаге код компонентов модели данных зависит от их интерфейса, принятого на шаге определения архитектуры приложения. Вариант кода компонентов модели данных приложения и их отображения на таблицы и поля БД приведены в Приложении 4.
Определение архитектуры пользовательского интерфейса приложения На этом шаге определяется набор основных форм приложения и схема навигации между ними. При наличии требований по защите доступа к различным элементам приложения, определяется политика защиты и методы защиты отдельных форм и потоков данных, в тои числе, методы аутентификации и авторизации пользователей, используемые протоколы аутентификации и пр. От данного приложения требуется предоставлять всем пользователям возможность просматривать данные о книгах, а выделенным пользователям — возможность редактирования этих данных. В результате выполнения этого шага должен быть определен набор форм приложения, функции каждой из форм, схема навигации между формами, а также защищенные области приложения (группы форм с функциями, к которым должны иметь доступ только пользователи в рамках определенных ролей) и способы реализации защиты доступа к каждой из таких областей. Решения, касающиеся защищенных областей и способов их защиты, зависят от общей схемы защиты, принятой на шаге определения архитектуры приложения. Вариант архитектуры пользовательского интерфейса разрабатываемого приложения приведен в Приложении 5.
Проектирование отдельных форм приложения На этом шаге определяются набор функций и возможностей, предоставляемых каждой формой приложения, и набор элементов управления на каждой из форм, используемых для выполнения этих функций и навигации. При проектировании отдельной формы учитываются аспекты удобства использования, относящиеся к реализуемым ею функциям. В результате этого шага должны быть получены точные описания или проекты всех форм приложения в визуальном редакторе. Для каждой формы должен быть определен ее набор элементов пользовательского интерфейса и информация, представленная в каждом информационном (не только управляющем) элементе. Вариант проекта форм представлен в Приложении 6.
Разработка отдельных форм приложения и их интеграция На этом шаге выполняется разработка форм, кода элементов управления, конфигурационных файлов приложения и пр. Здесь также осуществляется интеграция и отладка всех элементов приложения. По окончании этого шага должны быть получены следующие результаты.
5
•
Должен быть разработан код всех форм приложения, как страниц ASP.NET, так и поддерживающий их код на C#.
•
Должен быть доработан конфигурационный файл приложения — в нем должны быть отражены принятые решения по защите доступа к отдельным формам. При помещении форм из разных областей защиты в различные директории приложения должны быть разработаны отдельные конфигурационные файлы для всех таких директорий.
•
Разработанный код должен пройти отладку и модульное тестирование. Необходимые для этого модульные тесты должны быть спроектированы во время или до разработки кода.
•
Приложение в целом должно пройти системное тестирование. Системные тесты должны быть спроектированы заранее и основываться на сценариях использования данного приложения.
Варианты кода форм приложения и конфигурационных файлов представлены в Приложении 7. Варианты модульных и системных тестов приложения представлены в Приложении 8.
Приложение 1. Пример требований к разрабатываемому приложению и примеры вопросов по требованиям.
6
Для замечаний
Требования к создаваемому приложению Разрабатываемое приложение должно предоставлять возможности навигации по небольшой БД книжных изданий и редактирования имеющейся в ней информации о книгах. Основной код приложения должен быть написан на языке C#. 1. Пользовательский интерфейс. Пользовательский интерфейс приложения должен быть выполнен на основе Web. Базовой технологией для его разработки должна быть ASP.NET. a. Информация о книгах и навигация по БД. В качестве информации о книге должны присутствовать ее заглавие, фамилии и имена авторов, 10-символьный ISBN, год издания, название издательства и ссылка на страницу данной книги в одном из Интернетмагазинов. Интерфейс должен предоставлять пользователю возможность найти информацию о книге в БД по ее заголовку и фамилиям авторов. b. Редактирование информации о книгах. Возможность редактировать информацию о книгах, в том числе, добавлять записи о новых книгах, должна предоставляться только некоторым пользователям, список которых определяется администратором приложения. При редактировании информации о книгах должна использоваться уже имеющаяся в БД информация об издательствах и авторах книг. 2. БД приложения и связь с ней. БД приложения должна содержать все атрибуты книг, доступные через пользовательский интерфейс, и размещаться в одной из широко используемых реляционных СУБД: MS SQL Server, Oracle, MySQL, и т.п. Взаимодействие приложения с БД должно быть реализовано на базе среды интеграции NHibernate.
7
Возможные вопросы по требованиям к разрабатываемому приложению таковы. 1. Каковы функциональные требования к приложению? Какие задачи оно должно решать? 2. С какими данными приложение должно работать? Как они должны быть организованы? 3. Каковы требования к защите данных? Какие роли определяются в требованиях к приложению и какие права им предоставляются?
Приложение 2. Примеры определения архитектуры приложения. Возможный вариант многоуровневой архитектуры приложения изображен на Рис. 2. Клиентская часть интерфейса пользователя (Web-браузер)
Серверные компоненты интерфейса пользователя (Web-формы ASP.NET и HTML-страницы)
Компоненты модели данных приложения (Классы основных хранимых сущностей)
Среда интеграции модели данных и БД (NHibernate)
БД приложения (в рамках одной из реляционных СУБД)
Рисунок 2. Архитектура разрабатываемого приложения. Цветом выделены уже существующие компоненты, которые не нужно разрабатывать или модифицировать.
При использовании этого варианта в качестве выделенных цветом компонентов берутся уже существующие компоненты, интерфейс взаимодействия Web-браузера с компонентами ASP.NET поддерживается средой .NET, компоненты модели данных определяют собственный интерфейс для работы с данными, их взаимодействие со средой интеграции NHibernate и ее взаимодействие с СУБД поддерживается самой средой NHibernate. Варианты определения интерфейса компонентов модели данных. 1. Первый вариант. Минимальный интерфейс, при помощи которого можно только читать и изменять значения полей. Определяются классы Author, Book и Publisher, представляющие данные об авторах, книгах и издательствах. Для каждого поля данных в них определяются методы get и set. 8
2. Второй вариант. Расширенный интерфейс. Так же, как в предыдущем случае, определяются классы Author, Book и Publisher, методы get и set для всех полей данных. Кроме этого, выделяются используемые в компонентах ASP.NET запросы к данным — для этого, однако, надо достаточно детально представить реализацию этих компонентов. Примеры таких запросов: «выдать всех авторов, чья фамилия начинается на заданную букву», «выдать все книги, чьи названия начинаются на заданную букву». Каждый такой запрос реализуется в виде отдельного метода в соответствующем компоненте модели данных. Варианты определения схемы защиты данных приложения. Во всех вариантах определяются роли «обычный пользователь», «привилегированный пользователь» и «администратор». Обычный пользователь может только просматривать информацию о книгах, искать книги и пр. Привилегированный пользователь может добавлять, удалять и редактировать информацию о книгах, авторах и издательствах. Администратор может добавлять и удалять привилегированных пользователей, определяя их учетные записи (login) и пароли. Во всех предлагаемых вариантах для реализации защиты приложения используются встроенные механизмы ASP.NET. Возможные способы определения привилегированных пользователей могут различаться. 1. У администратора нет специального пользовательского интерфейса. Список привилегированных пользователей с их именами и паролями хранится в БД приложения в особой таблице. При необходимости администратор изменяет его напрямую при помощи инструментов администрирования СУБД или выполнения SQL-скриптов. 2. У администратора нет специального пользовательского интерфейса. Список привилегированных пользователей с их именами и паролями содержится в конфигурационном файле приложения. При необходимости администратор изменяет его напрямую, редактируя конфигурационный файл на Web-сервере. 3. У администратора есть специальный интерфейс, доступ к которому возможен только после аутентификации — указания учетной записи (login) и пароля администратора. Список привилегированных пользователей с их именами и паролями хранится в БД приложения в особой таблице. Администратор изменяет его при помощи этого специализированного интерфейса.
Приложение 3. Пример схемы БД приложения и SQL-скриптов для ее создания. Вариант определения схемы БД приложения с использованием специальной таблицы для хранения имен и паролей привилегированных пользователей приведен на Рис. 3. Соответствующий код на SQL, создающий такую БД в рамках СУБД MySQL 5.0, приведен ниже. Другие варианты схемы БД: 1. Все то же самое, но нет специальной таблицы PrivilegedUser. В этом случае привилегированные пользователи и их пароли должны описываться в конфигурационном файле приложения. 2. Все то же самое, но связь между таблицами Book и Publisher имеет тип «многие-ко многим». В этом случае должна появиться дополнительная таблица BookPublishers
9
с двумя полями-ссылками на первичные ключи Book и Publisher. В таблице Book при этом отсутствует поле PublisherID.
Рисунок 3. Примерная схема БД приложения.
Следующий скрипт создает БД в соответствии со схемой, изображенной на Рис. 3. /* Create schema library */ CREATE DATABASE IF NOT EXISTS library; USE library; /* Definition of table `library`.`author` */ DROP TABLE IF EXISTS `library`.`author`; CREATE TABLE `library`.`author` ( `AuthorID` int unsigned NOT NULL default '0' , `Surname` varchar(50) NOT NULL default '' , `FirstName` varchar(50) default NULL, `RestNames` varchar(255) default NULL, PRIMARY KEY (`AuthorID`), KEY `Authors` (`Surname`) ) DEFAULT CHARSET=utf8; /* Definition of table `library`.`publisher` */ DROP TABLE IF EXISTS `library`.`publisher`; CREATE TABLE `library`.`publisher` ( `PublisherID` int unsigned NOT NULL default '0', `Title` varchar(255) NOT NULL default '', PRIMARY KEY (`PublisherID`), KEY `Publishers` (`Title`) ) DEFAULT CHARSET=utf8; /* Definition of table `library`.`book` */ DROP TABLE IF EXISTS `library`.`book`; CREATE TABLE `library`.`book` ( `BookID` int unsigned NOT NULL default `Title` varchar(255) NOT NULL default `ISBN` varchar(10) default `Year` int unsigned default `Link` varchar(500) default `PublisherID` int unsigned default
'0' , '' , NULL, NULL, NULL, NULL,
10
PRIMARY KEY (`BookID`) , KEY `Books` (`Title`) , KEY `PublisherID` (`PublisherID`), CONSTRAINT `PublisherID` FOREIGN KEY (`PublisherID`) REFERENCES `publisher` (`PublisherID`) ON DELETE SET NULL ) DEFAULT CHARSET=utf8; /* Definition of table `library`.`bookauthors` */ DROP TABLE IF EXISTS `library`.`bookauthors`; CREATE TABLE `library`.`bookauthors` ( `AuthorID` int unsigned NOT NULL, `BookID` int unsigned NOT NULL, PRIMARY KEY (`BookID`,`AuthorID`), KEY `AuthorBooks` (`BookID`) , KEY `BookAuthors` (`AuthorID`) , CONSTRAINT `AuthorBooks` FOREIGN KEY (`BookID`) REFERENCES `book` (`BookID`) ON DELETE CASCADE, CONSTRAINT `BookAuthors` FOREIGN KEY (`AuthorID`) REFERENCES `author` (`AuthorID`) ON DELETE CASCADE ) DEFAULT CHARSET=utf8; /* Definition of table `library`.`privilegeduser` */ DROP TABLE IF EXISTS `library`.`privilegeduser`; CREATE TABLE `library`.`privilegeduser` ( `UserID` int unsigned NOT NULL default '0', `Login` varchar(50) NOT NULL, `Password` varchar(255) NOT NULL, PRIMARY KEY (`UserID`) ) DEFAULT CHARSET=utf8;
Замечание. При использовании таблиц формата MyISAM (действует по умолчанию) определенные ограничения ссылочной целостности не контролируются MySQL. Для включения автоматической проверки ссылочной целостности надо использовать таблицы формата InnoDB. Следующий скрипт заполняет описанную БД приложения некоторым набором данных. INSERT ( 1, ( 2, ( 3, ( 4, ( 5, ( 6, ( 7, ( 8, ( 9, ( 10, ( 11, ( 12, ( 13, ( 14,
INTO `library`.`author` 'Somerville', 'Ian' 'Booch' , 'Grady' 'Rumbaugh' , 'James' 'Jacobson' , 'Ivar' 'Tanenbaum' , 'Andrew' 'van Steen' , 'Maarten' 'Bass' , 'Len' 'Clements' , 'Paul' 'Kazman' , 'Rick' 'Klein' , 'Mark' 'Royce' , 'Walker' 'Beck' , 'Kent' 'Fowler' , 'Martin' 'Szyperski' , 'Clemens'
( `AuthorID`, `Surname`, `FirstName` ) VALUES ), ), ), ), ), ), ), ), ), ), ), ), ), );
INSERT INTO `library`.`publisher` ( `PublisherID`, `Title` ) VALUES ( 1, 'Addison-Wesley' ), ( 2, 'Prentice Hall' ); INSERT INTO `library`.`book` ( `BookID`, `ISBN`, `Year`, `PublisherID`, `Title`, `Link` ) VALUES
11
( 1, '0805353402', 1994, 1, 'Object-Oriented Analysis and Design with Applications', 'http://www.amazon.com/Object-Oriented-Analysis-DesignApplications-2nd/dp/0805353402' ), ( 2, '0321267974', 2005, 1, 'Unified Modeling Language User Guide', 'http://www.amazon.com/Unified-Modeling-Language-User-Guide/dp/0201571684' ), ( 3, '0321245628', 2005, 1, 'Unified Modeling Language Reference Manual', 'http://www.amazon.com/Modeling-Language-Reference-Addison-WesleyTechnology/dp/0321245628' ), ( 4, '0201571692', 1999, 1, 'The Unified Software Development Process', 'http://www.amazon.com/Unified-Software-Development-Process/dp/0201571692' ), ( 5, '0321210263', 2004, 1, 'Software Engineering', 'http://www.amazon.com/Software-Engineering-International-ComputerScience/dp/0321210263' ), ( 6, '0130661023', 2003, 2, 'Computer Networks', 'http://www.amazon.com/Computer-Networks-Fourth-AndrewTanenbaum/dp/0130661023' ), ( 7, '0130888931', 2002, 2, 'Distributed Systems: Principles and Paradigms', 'http://www.amazon.com/Distributed-Systems-Principles-AndrewTanenbaum/dp/0130888931' ), ( 8, '0130313580', 2001, 2, 'Modern Operating Systems', 'http://www.amazon.com/Modern-Operating-Systems-AndrewTanenbaum/dp/0130313580' ), ( 9, '0805305947', 1996, 1, 'Object Solutions: Managing the Object-Oriented Project', 'http://www.amazon.com/Object-Solutions-Managing-Object-OrientedProject/dp/0805305947' ), ( 10, '0321154959', 2003, 1, 'Software Architecture in Practice', 'http://www.amazon.com/Software-Architecture-Practice-SecondBass/dp/0321154959' ), ( 11, '020170482X', 2001, 1, 'Evaluating Software Architectures: Methods and Case Studies', 'http://www.amazon.com/Evaluating-Software-ArchitecturesMethods-Studies/dp/020170482X' ), ( 12, '0201309580', 1998, 1, 'Software Project Management: A Unified Framework', 'http://www.amazon.com/Software-Project-Management-UnifiedFramework/dp/0201309580' ), ( 13, '0201710919', 2000, 1, 'Planning Extreme Programming', 'http://www.amazon.com/Planning-Extreme-Programming-Kent-Beck/dp/0201710919' ), ( 14, '0201895420', 1996, 1, 'Analysis Patterns: Reusable Object Models', 'http://www.amazon.com/Analysis-Patterns-Reusable-Object-OrientedEngineering/dp/0201895420' ), ( 15, '0201745720', 2002, 1, 'Component Software: Beyond Object-Oriented Programming', 'http://www.amazon.com/Component-Software-Beyond-ObjectOriented-Programming/dp/0201178885' ); INSERT INTO `library`.`bookauthors` ( `AuthorID`, `BookID` ) VALUES (2,1), (2,2), (3,2), (4,2), (2,3), (3,3), (4,3), (2,4), (3,4), (4,4), (1,5), (5,6), (5,7), (6,7), (5,8), (2,9), (7,10), (8,10), (9,10),
12
(8,11), (9,11), (10,11), (11,12), (12,13), (13,13), (13,14), (14,15); INSERT INTO `library`.`privilegeduser` ( `UserID`, `Login`, `Password` ) VALUES ( 1, 'lib_admin', 'nimda_bil2006' );
Приложение 4. Пример кода компонентов модели данных приложения и описания их отображения на БД. Ниже приведен примерный код классов C#, объекты которых представляют хранимые данные приложения. using System; using System.Collections; namespace CMC.SDT.Library { public class Author { private int id; private string firstName; private string surname; private string restNames; private ICollection books; public virtual int ID { get { return id; } set { id = value; } } public virtual string FirstName { get { return firstName; } set { firstName = value; } } public virtual string Surname { get { return surname; } set { surname = value; } } public virtual string RestNames { get { return restNames; } set { restNames = value; } } public virtual ICollection Books { get { return books; }
13
set { books = value; } } } public class Publisher { private int id; private string title; private ICollection books; public virtual int ID { get { return id; } set { id = value; } } public virtual string Title { get { return title; } set { title = value; } } public virtual ICollection Books { get { return books; } set { books = value; } } } public class Book { private int id; private string title; private string isbn; private string file; private int year; private Publisher publisher; private ICollection authors; public virtual int ID { get { return id; } set { id = value; } } public virtual string Title { get { return title; } set { title = value; } } public virtual string ISBN { get { return isbn; } set { isbn = value; } } public virtual string File { get { return file; } set { file = value; } } public virtual int Year
14
{ get { return year; } set { year = value; } } public virtual Publisher Publisher { get { return publisher; } set { publisher = value; } } public virtual ICollection Authors { get { return authors; } set { authors = value; } } } public class PrivilegedUser { private int id; private string login; private string password; public virtual int ID { get { return id; } set { id = value; } } public virtual string Login { get { return login; } set { login = value; } } public virtual string Password { get { return password; } set { password = value; } } } }
Для каждого класса хранимых объектов необходимо определить отображение данных (свойств) этих объектов на таблицы БД и их поля. Описание этого отображения находится в конфигурационных файлах NHibernate. Для каждого класса хранимых объектов необходимо определить отображение данных (свойств) этих объектов на таблицы БД и их поля. Это отображение определяется в конфигурационных файлах NHibernate. Схема описываемого им отображения показана на Рис. 4.
15
Рисунок 4. Схема отображения классов модели данных и их свойств на таблицы и поля БД.
Для приведенных выше компонентов модели данных и изображенной на Рис. 3 БД такое отображение выглядит следующим образом. <property name="Surname" column="Surname" type="String"/> <property name="FirstName" column="FirstName" type="String"/> <property name="RestNames" column="RestNames" type="String"/> <set name="Books" lazy="true" table="bookauthors"> <many-to-many column="BookID"/> <property name="Title" column="Title" type="String"/> <set name="Books" inverse="true" lazy="true">
16
<property name="Title" column="Title" type="String"/> <property name="ISBN" column="ISBN" type="String"/> <property name="Link" column="Link" type="String"/> <property name="Year" column="Year" type="Int32"/> <many-to-one name="Publisher" column="PublisherID"/> <set name="Authors" inverse="true" lazy="true" table="bookauthors"> <many-to-many column="AuthorID"/> <property name="Login" column="login" type="String"/> <property name="Password" column="password" type="String"/>
Помимо классов хранимых сущностей удобно использовать дополнительный класс для управления сессиями в NHibernate — открытия и закрытия сессий, транзакций, создания запросов и пр. Вариант его кода приведен ниже. using using using using
System; System.Web; NHibernate; NHibernate.Cfg;
namespace CMC.SDT.Library { public class NHibernateHelper { private const string CurrentSessionKey = "nhibernate.current_session"; private static readonly ISessionFactory sessionFactory; static NHibernateHelper() { sessionFactory = new Configuration().Configure() .AddFile("library.hbm.xml").BuildSessionFactory(); } public static ISession GetCurrentSession() { HttpContext context = HttpContext.Current; ISession currentSession; if(context == null) { currentSession = sessionFactory.OpenSession(); } else { currentSession = context.Items[CurrentSessionKey] as ISession; if (currentSession == null) {
17
currentSession = sessionFactory.OpenSession(); context.Items[CurrentSessionKey] = currentSession; } } return currentSession; } public static void CloseSession() { HttpContext context = HttpContext.Current; if(context == null) { return; } ISession currentSession = context.Items[CurrentSessionKey] as ISession; if (currentSession == null) { // No current session return; } currentSession.Close(); context.Items.Remove(CurrentSessionKey); } public static void CloseSessionFactory() { if (sessionFactory != null) { sessionFactory.Close(); } } } }
Приложение 5. Пример архитектуры пользовательского интерфейса приложения. Для тех вариантов, в которых отсутствует специализированный интерфейс администратора, предлагается следующий вариант архитектуры пользовательского интерфейса. Одна форма используется для навигации по БД книг и одна форма — для ее редактирования. Доступ ко второй форме предоставляется только пользователям, указанным в таблице PrivilegedUser, по указанному там же паролю. Для аутентификации пользователей используется дополнительная форма. Эта архитектура интерфейса приложения изображена на Рис. 5.
18
Браузер Интернет
Форма просмотра данных о книгах (возможности поиска)
Форма аутентификации пользователей
Форма редактирования данных о книгах (с использованием имеющейся информации об авторах и издательствах) Защищенная область — доступна только для привилегированных пользователей Рисунок 5. Возможная архитектура пользовательского интерфейса приложения.
Приложение 6. Пример проекта форм приложения. Ниже приведен проект форм приложения для архитектуры пользовательского интерфейса, представленной на Рис. 5. В рамках этой архитектуры имеется три формы.
Форма просмотра информации о книгах
Рисунок 6. Форма просмотра информации о книгах.
Эта форма — основная форма приложения. Она содержит заголовок-название приложения и набор информационных элементов для представления данных о книгах — фамилии и имени автора, названия книги названия издательства, ISBN книги и года издания. Форма может содержать информацию о нескольких книгах, поэтому для каждого из этих полей 19
отводится список. Фамилия и имя автора комбинируются в одну запись в соответствующем списке. Возможен поиск по автору и названию книги — для этого предназначены выпадающие списки над соответствующими списками. Эти выпадающие списки содержат комбинации фамилий и имен авторов, данные о которых есть в БД, и названия книг, занесенных в БД. При выборе в них автора или названия книги в списках появляется информация о всех книгах, у которых выбранный автор является единственным автором или одним из соавторов, или информация о выбранной книге, включая имена и фамилии всех ее авторов. Замечание. Если БД содержит много (>100) записей о книгах и авторах, необходимо разработать другой интерфейс для поиска по авторам и названиям книг. Варианты — поиск по первой букве или нескольким первым буквам фамилии автора или названия книги, или отдельные станицы для представления списков книг, чье название начинается на данную букву, и отдельные страницы для списков книг авторов, чья фамилия начинается на данную букву. При выделении одной из книг, информация о которых представлена в списках, выделяются все соответствующие записи во всех списках. Кроме того, становятся доступны ссылка на страницу данной книги в одном из Интернет-магазинов и ссылка на форму редактирования информации. Имеется две ссылки, ведущие на форму редактирования информации о книгах. Первая всегда доступна и приводит (после аутентификации) к открытию пустой формы, с помощью которой можно добавить информацию о новой книге. Вторая доступна, только когда выделена информация о некоторой книге, и ведет на форму, заполненную уже имеющейся в БД информацией об этой книге. С ее помощью можно эту информацию изменить.
Форма аутентификации привилегированных пользователей
Рисунок 7. Форма аутентификации.
Форма аутентификации содержит два поля для ввода имени пользователя и пароля и кнопку, запускающую процедуру аутентификации. При неудачной аутентификации снизу от кнопки появляется сообщение о том, что либо пользователь системе неизвестен, либо пароль введен неправильно. После 5-й неуспешной попытки аутентификации, нажатие на эту кнопку переводит на основную форму приложения. При успешной аутентификации открывается форма редактирования информации о книгах, пустая или заполненная данными выделенной книги.
20
Форма редактирования информации о книгах
Рисунок 8. Форма редактирования информации о книгах.
Эта форма позволяет как ввести информацию о новой книге, так и изменить данные об уже имеющейся в БД книге. Значение, выбранное в выпадающем списке Number of authors, определяет число однотипных групп полей для данных об авторе, показанных внизу формы. Это число изменяется от 1 до 10. Выпадающие списки справа от поля, где вводится название издательства, и справа от группы полей данных об авторе позволяют выбрать уже имеющихся в БД издательство и автора. Производятся следующие проверки корректности введенных данных. •
Должно быть введено непустое название книги.
•
Должно быть указано издательство.
•
Должен быть указано хотя бы один автор. Для указания автора должна быть определена его фамилия. Число указанных авторов должно совпадать с числом авторов, указанным в поле Number of authors.
•
Размеры всех строк, указанных в качестве значений полей, не должны превосходить максимально возможные размеры соответствующих полей БД.
•
Поле ISBN должно быть пусто или в нем должно быть ровно 10 символов, из которых все, кроме последнего — цифры, а последний — цифра или буква ‘X’.
•
В качестве года издания должно быть введено целое положительное число или же это поле должно быть пусто.
При нажатии в любой момент на ссылку Cancel происходит сброс всех введенных данных и переключение на основную форму приложения.
21
При нажатии на ссылку Save происходит запись введенных данных, если они корректны, в БД приложения. В качестве активной остается эта же форма, все данные во всех полях сохраняются.
Приложение 7. Пример конфигурационных файлов и кода форм приложения. Здесь приведен вариант размещения файлов приложения, оформления конфигурационных файлов, а также вариант кода двух форм из представленных в проекте в Приложении 6.
Расположение файлов приложения и конфигурационные файлы Файлы приложения расположены в двух директориях. Основная форма и вспомогательный код помещается в директории верхнего уровня. Форма редактирования и форма аутентификации, а также код, поддерживающий их работу, помещен в поддиректорию SECURE.
Рисунок 9. Размещение файлов проекта.
Для основной директории приложения автоматически созданный в среде Microsoft Visual Studio конфигурационный файл был исправлен в двух местах. Первое исправление предназначено для подключения среды NHibernate и задействованных в ее работе драйверов СУБД. Ниже представлен вариант (начало) кода конфигурационного файла, в котором описано использование СУБД MySQL. <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" /> ...
В конфигурационном файле директории SECURE нужно указать только запрет доступа для анонимных пользователей. Ниже приведен код этого файла целиком. <system.web>
of of of of
users]" roles]"/> users]" roles]"/>
23
Основная форма приложения На Рис. 10 можно увидеть ее в графическом редакторе Web-форм в Microsoft Visual Studio.
Рисунок 10. Форма просмотра информации о книгах в редакторе форм.
Соответствующий код HTML-страницы представлен ниже. Library Navigator <meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR"> <meta content="C#" name="CODE_LANGUAGE"> <meta content="JavaScript" name="vs_defaultClientScript"> <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema"> Library Navigator Author Book Title Publisher
24
ISBN Year Add new Edit Link
Пример кода вспомогательного класса MainForm, реализующего обработку действий пользователя на основной форме приложения, представлен ниже. using using using using using using using using using using
System; System.Collections; System.ComponentModel; System.Data; System.Drawing; System.Web; System.Web.SessionState; System.Web.UI; System.Web.UI.WebControls; System.Web.UI.HtmlControls;
using NHibernate; namespace CMC.SDT.Library { /// <summary> /// Summary description for WebForm1. /// public class MainForm : System.Web.UI.Page { protected System.Web.UI.WebControls.Label Label1; protected System.Web.UI.WebControls.Label Label2; protected System.Web.UI.WebControls.Label Label3; protected System.Web.UI.WebControls.Label Label4; protected System.Web.UI.WebControls.Label Label5; protected System.Web.UI.WebControls.DropDownList authorList; protected System.Web.UI.WebControls.ListBox authorListBox; protected System.Web.UI.WebControls.ListBox titleListBox; protected System.Web.UI.WebControls.ListBox publisherListBox; protected System.Web.UI.WebControls.ListBox ISBNListBox; protected System.Web.UI.WebControls.ListBox yearListBox; protected System.Web.UI.WebControls.HyperLink getLink; protected System.Web.UI.WebControls.HyperLink addLink; protected System.Web.UI.WebControls.HyperLink editLink;
25
protected System.Web.UI.WebControls.DropDownList titleList; private void Page_Load(object sender, System.EventArgs e) { // Put user code to initialize the page here if(authorList.Items.Count == 0) { authorList.Items.Insert(0, "*"); titleList.Items.Insert(0, "*"); ISession session = NHibernateHelper.GetCurrentSession(); ITransaction tx = session.BeginTransaction(); IQuery authorQuery = session.CreateQuery ("select a from Author as a order by a.Surname"); IQuery bookQuery = session.CreateQuery ("select b from Book as b order by b.Title"); ListItem item; foreach(Author a in authorQuery.Enumerable()) { item = new ListItem(a.Surname + ", " + a.FirstName, a.ID.ToString()); authorList.Items.Add(item); } foreach(Book b in bookQuery.Enumerable()) { item = new ListItem(b.Title, b.ID.ToString()); titleList.Items.Add(item); } tx.Commit(); NHibernateHelper.CloseSession(); } } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { // // CODEGEN: This call is required by the ASP.NET Web Form Designer. // InitializeComponent(); base.OnInit(e); } /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.authorList.SelectedIndexChanged += new System.EventHandler(this.authorList_SelectedIndexChanged); this.yearListBox.SelectedIndexChanged += new System.EventHandler(this.yearListBox_SelectedIndexChanged); this.ISBNListBox.SelectedIndexChanged += new System.EventHandler(this.ISBNListBox_SelectedIndexChanged); this.publisherListBox.SelectedIndexChanged += new System.EventHandler(this.publisherListBox_SelectedIndexChanged);
26
this.titleList.SelectedIndexChanged += new System.EventHandler(this.titleList_SelectedIndexChanged); this.authorListBox.SelectedIndexChanged += new System.EventHandler(this.authorListBox_SelectedIndexChanged); this.titleListBox.SelectedIndexChanged += new System.EventHandler(this.titleListBox_SelectedIndexChanged); this.Load += new System.EventHandler(this.Page_Load); } #endregion private void authorList_SelectedIndexChanged (object sender, System.EventArgs e) { if((sender as DropDownList).SelectedIndex == 0) { authorListBox.Items.Clear(); titleListBox.Items.Clear(); publisherListBox.Items.Clear(); ISBNListBox.Items.Clear(); yearListBox.Items.Clear(); getLink.Enabled = false; return; } int selID = Int32.Parse((sender as DropDownList).SelectedItem.Value); string selAuth = (sender as DropDownList).SelectedItem.Text; ISession session = NHibernateHelper.GetCurrentSession(); ITransaction tx = session.BeginTransaction(); IQuery query = session.CreateQuery ("select a, b from Author a, Book b where a.ID = :ID " + "and b in elements(a.Books)"); query.SetString("ID", selID.ToString()); ListItem item; Book b; authorListBox.Items.Clear(); titleListBox.Items.Clear(); publisherListBox.Items.Clear(); ISBNListBox.Items.Clear(); yearListBox.Items.Clear(); getLink.Enabled = false; titleList.SelectedIndex = 0; foreach(object[] arr in query.Enumerable()) { b = arr[1] as Book; item = new ListItem(selAuth, b.ID.ToString()); authorListBox.Items.Add(item); item = new ListItem(b.Title, b.ID.ToString()); titleListBox.Items.Add(item); item = new ListItem(b.Publisher.Title, b.ID.ToString()); publisherListBox.Items.Add(item);
27
item = new ListItem(b.ISBN, b.ID.ToString()); ISBNListBox.Items.Add(item); item = new ListItem(b.Year.ToString(), b.ID.ToString()); yearListBox.Items.Add(item); } tx.Commit(); NHibernateHelper.CloseSession(); } private void titleList_SelectedIndexChanged (object sender, System.EventArgs e) { if((sender as DropDownList).SelectedIndex == 0) { authorListBox.Items.Clear(); titleListBox.Items.Clear(); publisherListBox.Items.Clear(); ISBNListBox.Items.Clear(); yearListBox.Items.Clear(); getLink.Enabled = false; return; } int selID = Int32.Parse((sender as DropDownList).SelectedItem.Value); string selTitle = (sender as DropDownList).SelectedItem.Text; ISession session = NHibernateHelper.GetCurrentSession(); ITransaction tx = session.BeginTransaction(); IQuery query = session.CreateQuery ("select a, b from Author a, Book b where b.ID = :ID " + "and a in elements(b.Authors)"); query.SetString("ID", selID.ToString()); ListItem item; Author a; Book b; authorListBox.Items.Clear(); titleListBox.Items.Clear(); publisherListBox.Items.Clear(); ISBNListBox.Items.Clear(); yearListBox.Items.Clear(); getLink.Enabled = false; authorList.SelectedIndex = 0; foreach(object[] arr in query.Enumerable()) { a = arr[0] as Author; b = arr[1] as Book; item = new ListItem(a.Surname + ", " + a.FirstName, b.ID.ToString()); authorListBox.Items.Add(item); item = new ListItem(selTitle, b.ID.ToString()); titleListBox.Items.Add(item); item = new ListItem(b.Publisher.Title, b.ID.ToString());
28
publisherListBox.Items.Add(item); item = new ListItem(b.ISBN, b.ID.ToString()); ISBNListBox.Items.Add(item); item = new ListItem(b.Year.ToString(), b.ID.ToString()); yearListBox.Items.Add(item); } tx.Commit(); NHibernateHelper.CloseSession(); } private void authorListBox_SelectedIndexChanged (object sender, System.EventArgs e) { int selInd = (sender as ListBox).SelectedIndex; authorListBox.SelectedIndex = selInd; titleListBox.SelectedIndex = selInd; publisherListBox.SelectedIndex = selInd; ISBNListBox.SelectedIndex = selInd; yearListBox.SelectedIndex = selInd; ISession session = NHibernateHelper.GetCurrentSession(); ITransaction tx = session.BeginTransaction(); IQuery query = session.CreateQuery ("select b from Book b where b.ID = :ID"); query.SetString("ID", (titleListBox as ListBox).SelectedValue); foreach(Book b in query.Enumerable()) { getLink.NavigateUrl = b.Link; break; } getLink.Enabled = true; tx.Commit(); NHibernateHelper.CloseSession(); } private void titleListBox_SelectedIndexChanged (object sender, System.EventArgs e) { int selInd = (sender as ListBox).SelectedIndex; authorListBox.SelectedIndex = selInd; titleListBox.SelectedIndex = selInd; publisherListBox.SelectedIndex = selInd; ISBNListBox.SelectedIndex = selInd; yearListBox.SelectedIndex = selInd; ISession session = NHibernateHelper.GetCurrentSession(); ITransaction tx = session.BeginTransaction(); IQuery query = session.CreateQuery ("select b from Book b where b.ID = :ID"); query.SetString("ID", (titleListBox as ListBox).SelectedValue); foreach(Book b in query.Enumerable()) { getLink.NavigateUrl = b.Link; break;
29
} getLink.Enabled = true; tx.Commit(); NHibernateHelper.CloseSession(); } private void publisherListBox_SelectedIndexChanged (object sender, System.EventArgs e) { int selInd = (sender as ListBox).SelectedIndex; authorListBox.SelectedIndex = selInd; titleListBox.SelectedIndex = selInd; publisherListBox.SelectedIndex = selInd; ISBNListBox.SelectedIndex = selInd; yearListBox.SelectedIndex = selInd; getLink.Enabled = true; } private void ISBNListBox_SelectedIndexChanged (object sender, System.EventArgs e) { int selInd = (sender as ListBox).SelectedIndex; authorListBox.SelectedIndex = selInd; titleListBox.SelectedIndex = selInd; publisherListBox.SelectedIndex = selInd; ISBNListBox.SelectedIndex = selInd; yearListBox.SelectedIndex = selInd; ISession session = NHibernateHelper.GetCurrentSession(); ITransaction tx = session.BeginTransaction(); IQuery query = session.CreateQuery ("select b from Book b where b.ID = :ID"); query.SetString("ID", (titleListBox as ListBox).SelectedValue); foreach(Book b in query.Enumerable()) { getLink.NavigateUrl = b.Link; break; } getLink.Enabled = true; tx.Commit(); NHibernateHelper.CloseSession(); } private void yearListBox_SelectedIndexChanged (object sender, System.EventArgs e) { int selInd = (sender as ListBox).SelectedIndex; authorListBox.SelectedIndex = selInd; titleListBox.SelectedIndex = selInd; publisherListBox.SelectedIndex = selInd; ISBNListBox.SelectedIndex = selInd; yearListBox.SelectedIndex = selInd; ISession session = NHibernateHelper.GetCurrentSession();
30
ITransaction tx = session.BeginTransaction(); IQuery query = session.CreateQuery ("select b from Book b where b.ID = :ID"); query.SetString("ID", (titleListBox as ListBox).SelectedValue); foreach(Book b in query.Enumerable()) { getLink.NavigateUrl = b.Link; break; } getLink.Enabled = true; tx.Commit(); NHibernateHelper.CloseSession(); } } }
Форма аутентификации Вид форма аутентификации в графическом редакторе форм Microsoft Visual Studio представлен на Рис. 11.
Рисунок 11. Форма аутентификации в редакторе форм.
Далее приведен HTML-код формы аутентификации. Login <meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1"> <meta name="CODE_LANGUAGE" Content="C#"> <meta name="vs_defaultClientScript" content="JavaScript"> <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5"> Login
31
User Password EditForm.aspx Label
На этой форме размещены три вспомогательных элемента-метки (Label), которые не видны при первой загрузке формы. Метка message используется для показа пользователю сообщения о неверно введенном имени или пароле. Она становится видна, только когда вводится неверное имя пользователя или неверный пароль. Метка notLabel используется для хранения текущего числа неудачных попыток аутентификации. Как только это число превосходит заданный предел, управление переключается на основную форму приложения. Эта метка не видна никогда. Метка returnURL используется для хранения ссылки, по которой нужно перейти в случае успешной аутентификации. Эта метка тоже чисто вспомогательная, никогда не видна. Код вспомогательного класса Login, реализующего обработку действий пользователя на форме аутентификации, приведен ниже. using using using using using using using using using using using
System; System.Collections; System.ComponentModel; System.Data; System.Drawing; System.Web; System.Web.SessionState; System.Web.UI; System.Web.UI.WebControls; System.Web.UI.HtmlControls; System.Web.Security;
using NHibernate; namespace CMC.SDT.Library { /// <summary>
32
/// Summary description for Login. /// public class Login : System.Web.UI.Page { protected System.Web.UI.WebControls.Label userLabel; protected System.Web.UI.WebControls.Label passwordLabel; protected System.Web.UI.WebControls.TextBox userTextBox; protected System.Web.UI.WebControls.TextBox passwordTextBox; protected System.Web.UI.WebControls.Label returnURL; protected System.Web.UI.WebControls.Label message; protected System.Web.UI.WebControls.Button loginButton; protected System.Web.UI.WebControls.Label notLabel; protected const int maxNumberOfTrials = 5; protected int numberOfTrials = 0; private void Page_Load(object sender, System.EventArgs e) { // Put user code to initialize the page here if(notLabel.Text == null || notLabel.Text.Equals("")) { notLabel.Text = "0"; if(Request.QueryString["ReturnUrl"] != null) returnURL.Text = Request.QueryString["ReturnUrl"]; } else { numberOfTrials = Int32.Parse(notLabel.Text)+1; notLabel.Text = numberOfTrials.ToString(); message.Visible = true; message.Text = "Unknown login or incorrect password, please, try again"; if(numberOfTrials >= maxNumberOfTrials) { Server.Transfer("../MainForm.aspx"); } } } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { // // CODEGEN: This call is required by the ASP.NET Web Form Designer. // InitializeComponent(); base.OnInit(e); } /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.loginButton.Click += new System.EventHandler (this.loginButton_Click); this.Load += new System.EventHandler(this.Page_Load); } #endregion private void loginButton_Click(object sender, System.EventArgs e)
33
{ ISession session = NHibernateHelper.GetCurrentSession(); ITransaction tx = session.BeginTransaction(); //int nt = Int32.Parse(numberOfTrials.Text); IQuery query = session.CreateQuery ("select u from PrivilegedUser u where u.Login = :Login"); query.SetString("Login", userTextBox.Text); foreach(PrivilegedUser u in query.Enumerable()) { if( (u.Password == null && passwordTextBox.Text.Equals("")) || u.Password.Equals(passwordTextBox.Text)) FormsAuthentication.RedirectFromLoginPage(userTextBox.Text, true); break; } tx.Commit(); NHibernateHelper.CloseSession(); } } }
Приложение 8. Примеры модульных и системных тестов для приложения. В этом приложении представлены варианты модульных тестов и системных тестов для описанных в Приложениях 5 и 6 архитектуры пользовательского интерфейса и проекта форм приложения.
Модульные тесты. Основная форма приложения и навигация с нее 1. Проверить, что в начальном состоянии видимые элементы управления формы не содержат никаких данных, ссылка для добавления новой книги активна, ссылка для редактирования книги неактивна, ссылка на страницу книги на одном из Интернетмагазинов неактивна. 2. Выбрать произвольного автора в выпадающем списке. Проверить, что форма заполняется информацией об его книгах. 3. Выполнить 2 для разных авторов последовательно. Проверить, что все работает так же (книги первого автора пропадают, книги второго появляются). 4. Выбрать автора с заведомо более чем одной книгой. Проверить, что форма заполняется информацией обо всех его книгах. 5. Выбрать название одной из книг в БД. Проверить, что форма заполняется информацией об этой книге. 6. Выделить одну из нескольких книг, информация о которых представлена на форме. Проверить, что подсвечиваются все соответствующие элементы всех (невыпадающих) списков. Проверить, что становятся активными ссылка для редактирования книги и ссылка на страницу книги в одном из Интернет-магазинов. 7. Выделить одну из нескольких книг, информация о которых представлена на форме и которые имеют ссылку на страницу в одном из Интернет-магазинов. Попробовать перейти на эту страницу. Проверить, что страница открывается.
34
8. Попробовать перейти по ссылке добавления новой книги, ни разу до этого не проводя аутентификации (или выполнив удаление файлов cookie в настройках браузера). Проверить, что открывается форма аутентификации. 9. Попробовать перейти по ссылке добавления новой книги, предварительно уже пройдя аутентификацию. Проверить, что открывается пустая форма редактирования информации о книгах. 10. Выделить одну из нескольких книг, информация о которых представлена на форме. Проверить, что ссылка редактирования активна. Попробовать перейти по ссылке редактирования, ни разу до этого не проводя аутентификации (или выполнив удаление файлов cookie в настройках браузера). Проверить, что открывается форма аутентификации. 11. Выделить одну из нескольких книг, информация о которых представлена на форме. Проверить, что ссылка редактирования активна. Попробовать перейти по ссылке редактирования предварительно уже пройдя аутентификацию. Проверить, что открывается форма редактирования информации о книгах, заполненная данными о выделенной книге.
Модульные тесты. Форма аутентификации и навигация с нее 1. Ввести неверное имя привилегированного пользователя и любой пароль. Нажать на кнопку Login. Проверить, что появляется сообщение о неверном имени пользователя или неправильном пароле и форма редактирования данных о книгах не появляется. 2. Ввести одно из имен привилегированных пользователей и неправильный пароль. Нажать на кнопку Login. Проверить, что появляется сообщение о неверном имени пользователя или неправильном пароле и форма редактирования данных о книгах не появляется. 3. Повторить 1 или 2 несколько раз. Выполнять все проверки каждый раз. Кроме того, проверить, что после заданного количества попыток форма аутентификации пропадает и появляется форма просмотра информации о книгах. 4. Ввести одно из имен привилегированных пользователей и его пароль. Нажать на кнопку Login. Проверить, что открывается форма редактирования данных о книгах.
Модульные тесты. Форма редактирования данных о книгах и навигация с нее 1. Проверить, что при пустой форме ссылка Cancel активна. 2. Выбрать название издательства из выпадающего списка. Проверить, что оно копируется в соответствующее поле редактирования. 3. Выбрать автора из выпадающего списка. Проверить, его фамилия и имя копируются в соответствующие поля редактирования. 4. Выбрать число авторов, большее 1. Проверить, что появляется соответствующее количество групп полей ввода для задания авторов. 5. Выбрать число авторов, меньшее, чем текущее. Проверить, что соответствующие группы полей ввода для задания авторов пропадают с формы. 6. Выполнить 2 для одного из авторов, кроме первого. Проверить, что все работает аналогично. 7. Ввести данные во все поля, кроме названия книги. Проверить, что ссылка Cancel активна. Проверить, что ссылка Save неактивна. 35
8. Ввести данные во все поля, кроме названия издательства. Проверить, что ссылка Cancel активна. Проверить, что ссылка Save неактивна. 9. Ввести данные во все поля, кроме фамилии одного из авторов книги. Проверить, что ссылка Cancel активна. Проверить, что ссылка Save неактивна. 10. Ввести название книги, название издательства, фамилии всех авторов. Проверить, что ссылка Cancel активна. Проверить, что ссылка Save активна. 11. Ввести некоторые данные. Проверить, что ссылка Cancel активна. Попробовать перейти по ссылке Cancel. Убедиться, что открывается форма просмотра информации о книгах. 12. Ввести название книги, название издательства, фамилии всех авторов. Ввести 10 цифр ISBN. Проверить, что ссылка Save активна. Попробовать перейти по ссылке Save. Проверить, что остается открытой форма редактирования данных о книгах, поля которой заполнены той же информацией. 13. Ввести название книги, название издательства, фамилии всех авторов. Ввести в поле ISBN меньше 10-ти символов. Проверить, что ссылка Save активна. Попробовать перейти по ссылке Save. Проверить, что выдается сообщение о неверно введенном ISBN. Проверить, что данные всех полей сохраняются. 14. Ввести название книги, название издательства, фамилии всех авторов. Ввести в поле ISBN 10 символов, использовав на предпоследнем месте буквенный символ. Проверить, что ссылка Save активна. Попробовать перейти по ссылке Save. Проверить, что выдается сообщение о неверно введенном ISBN. Проверить, что данные всех полей сохраняются. 15. Ввести название книги, название издательства, фамилии всех авторов. Ввести в поле ISBN 10 символов, последний символ — ‘Y’. Проверить, что ссылка Save активна. Попробовать перейти по ссылке Save. Проверить, что выдается сообщение о неверно введенном ISBN. Проверить, что данные всех полей сохраняются. 16. Ввести название книги, название издательства, фамилии всех авторов. Ввести в поле Year строку “198X”. Проверить, что ссылка Save активна. Попробовать перейти по ссылке Save. Проверить, что выдается сообщение о неверно введенном Year. Проверить, что данные всех полей сохраняются. 17. Ввести название книги, название издательства, фамилии всех авторов. Ввести в поле Year строку “-1990”. Проверить, что ссылка Save активна. Попробовать перейти по ссылке Save. Проверить, что выдается сообщение о неверно введенном Year. Проверить, что данные всех полей сохраняются. 18. Выполнить 12. Проверить, что ссылка Cancel активна. Попробовать перейти по ссылке Cancel. Убедиться, что открывается форма просмотра информации о книгах. Найти только что введенное название книги в выпадающем списке названий книг в БД. Выбрать его. Проверить, что в списках появляется только что введенная информация.
Системные тесты 1. Выполнив удаление файлов cookie в настройках браузера, открыть приложение. Выбрать автора. Проверить, что форма заполняется информацией об его книгах. Выделить одну из книг. Проверить, что подсвечиваются все соответствующие элементы всех (невыпадающих) списков. Проверить, что становятся активными ссылка для редактирования книги и ссылка на страницу книги в одном из Интернет-магазинов. Попробовать перейти по ссылке добавления новой книги. Проверить, что 36
открывается форма аутентификации. Ввести одно из имен привилегированных пользователей и неправильный пароль. Нажать на кнопку Login. Проверить, что появляется сообщение о неверном имени пользователя или неправильном пароле и форма редактирования данных о книгах не появляется. Снова ввести неверные имя пользователя и пароль. Нажать на кнопку Login. Повторять это несколько раз. Каждый раз проверять, что сообщение не исчезает и форма редактирования данных о книгах не появляется. Проверить, что после заданного количества попыток снова открывается форма просмотра информации о книгах. Выбрать название книги из выпадающего списка. Проверить, что форма заполняется данными этой книги. Закрыть приложение. 2. Выполнив удаление файлов cookie в настройках браузера, открыть приложение. Выбрать автора с заведомо более, чем одной книгой. Проверить, что форма заполняется информацией обо всех его книгах. Выделить одну из книг. Проверить, что подсвечиваются все соответствующие элементы всех (невыпадающих) списков. Проверить, что становятся активными ссылка для редактирования книги и ссылка на страницу книги в одном из Интернет-магазинов. Попробовать перейти по ссылке добавления новой книги. Проверить, что открывается форма аутентификации. Ввести одно из имен привилегированных пользователей и неправильный пароль. Нажать на кнопку Login. Проверить, что появляется сообщение о неверном имени пользователя или неправильном пароле и форма редактирования данных о книгах не появляется. Ввести одно из имен привилегированных пользователей и его пароль. Нажать на кнопку Login. Проверить, что открывается пустая форма редактирования данных о книгах. Выбрать название издательства из выпадающего списка. Проверить, что оно копируется в соответствующее поле редактирования. Выбрать автора из выпадающего списка. Проверить, его фамилия и имя копируются в соответствующие поля редактирования. Выбрать число авторов, равное 2. Проверить, что появляется дополнительная группа полей ввода для задания авторов. Проверить, что данные о первом авторе сохраняются. Ввести в текстовые поля фамилию и имя второго автора. Ввести название книги. Проверить, что ссылка Save активна. Попробовать перейти по ссылке Save. Проверить, что остается открытой форма редактирования данных о книгах, поля которой заполнены той же информацией. Проверить, что ссылка Cancel активна. Попробовать перейти по ссылке Cancel. Убедиться, что открывается форма просмотра информации о книгах. Найти среди авторов в выпадающем списке фамилию и имя только что введенного. Выбрать его и проверить, что форма заполняется только что введенными данными о книге. Закрыть приложение. 3. Открыть приложение, предварительно пройдя аутентификацию, не позже, чем за 15 минут до этого. Выбрать автора с заведомо более, чем одной книгой. Проверить, что форма заполняется информацией обо всех его книгах. Выделить одну из книг. Проверить, что подсвечиваются все соответствующие 37
элементы всех (невыпадающих) списков. Проверить, что становятся активными ссылка для редактирования книги и ссылка на страницу книги в одном из Интернет-магазинов. Попробовать перейти по ссылке редактирования. Проверить, что открывается форма редактирования информации о книгах, заполненная данными о выделенной книге. Изменить название книги и год издания. В качестве года издания ввести 0. Проверить, что ссылка Save активна. Попробовать перейти по ссылке Save. Проверить, что появляется сообщение о неверном годе издания. Исправить год издания на положительное число. Проверить, что ссылка Save активна. Попробовать перейти по ссылке Save. Проверить, что остается открытой форма редактирования данных о книгах, поля которой заполнены той же информацией. Проверить, что ссылка Cancel активна. Попробовать перейти по ссылке Cancel. Убедиться, что открывается форма просмотра информации о книгах. Найти среди названий книг в выпадающем списке только что измененное название. Выбрать его и проверить, что форма заполняется только что введенными данными о книге. Закрыть приложение.
38