Книги, научные публикации Pages:     | 1 | 2 | 3 | 4 |   ...   | 5 |

том 2 альманах програ иста Тематический сборник материалов Library и Magazine ASP.NET Web-сервис Web-приложения альманах программиста Составитель Ю. Е. ...

-- [ Страница 2 ] --

Хотя само по себе это не угрожает приложения, хранение состояния отображения на клиенте несет потенциальную угрозу, посколь ку соответствующая информация содержится во всех и передается ими Web-серверу для обработки.

т Help /> /> Рис. 1. можно увидеть в исходном тексте страницы Хотя состояние отображения легко доступно в скрытом поле VIEW STATE, это не открытый текст. По умолчанию на основе данных из состо яния отображения вычисляется код, специфичный для компьютера и добавляемый к строке этого состояния. Полученный текст кодируется по основанию Base64, но не шифруется. Если защита данных все же нужна, единственное решение в этом случае Ч применение поскольку этот протокол защищает не только состояние отображе ния, но и все данные, пересылаемые страницей. Тем не менее вероятность декодирования состояния остается, хотя это не так-то просто с учетом не обходимости ряда недокументированных и внутрен них структур, а также из-за других трудностей. Учтите и что модифи кация состояния обычно обнаруживается сервером, который в этом случае генерирует исключение, связанное с защитой. Наконец, самое важное: со стояние отображения содержит данные, а не код. Если явно не задать ме нее строгие параметры защиты страницы, у хакера почти не будет возмож ности модифицировать состояние Если вы все же решили изменить параметры защиты устанавливаемые по умолчанию, будьте осторожны и помните о состоянии отображения, которое может оказаться уязвимым перед хакерами. Само по себе это обстоятельство не является в защите и позволяет только когда отключе ны базовые правила политики безопасности, предписывающие проверку допустимости и целостности данных. Но это, как вы более об щая проблема написания защищенного кода.

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

Для более надежной защиты состояния отображения ASP.NET-директива @Page поддерживает атрибут единственное назначе ние которого состоит в обнаружении любых попыток модификации состо яния отображения. (Аббревиатура расшифровывается как machine authentication check;

несмотря на то, что утверждается в документации, этот атрибут включен по умолчанию.) Если при сериализации атрибут ViewStateMac установлен в True, в состояние отображения добавля ется вычисляемая по алгоритму шифрования и ключу, задан ным в разделе файла По умолчанию приме няется алгоритм шифрования SHA1, а ключи для шифрования и дешиф рования генерируются автоматически и хранятся в подсистеме Local Security Authority (LSA) Web-сервера. Ч компонент операционных систем NT, Windows 2000 и Windows XP, который предоставляет сервисы и хранит сведения обо всех аспектах ло кальной защиты в системе.

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

Атрибут EnableViewStateMac директивы соответствует защищен ному члену страницы с тем же именем и по умолчанию равен True. Ниже показан фрагмент исходного кода, сгенерированного исполняющей средой ASP.NET для (Этот код можно найти во временной сис темной папке ASP.NET-приложения, если добавить к директиве атрибут override void { = = true;

Состояние отображения ASP.NET Если вас особенно беспокоит возможность атаки через состояние жения, просто следите за тем, чтобы атрибут был включен.

Будьте очень внимательны, применяя состояние отображения. Если вы используете параметры защиты по умолчанию, все в порядке. Я еще вер нусь к вопросам безопасности после обсуждения проблем производитель ности, и мы поговорим об альтернативной реализации состояния отобра жения, позволяющей решить проблему безопасности и уменьшить объем пересылаемых данных.

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

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

Состояние отображения экономит уйму времени, освобождая от дополни тельного кодирования, и, что важнее, упрощает работу программиста. Но если вы обнаруживаете, что такие удобства достаются слишком дорогой ценой, откажитесь от использования состояния отображения и инициали зируйте состояние серверных элементов управления заново при каждом возврате формы на сервер (postback). В этом случае отключение состояния отображения уменьшает время обработки и ускоряет загрузку страниц.

Состояние отображения можно отключить для всей присвоив false атрибуту EnableViewState директивы @Page:

<Х Хотя обычно это не рекомендуется, обязательно подумайте об отключении состояния отображения у страниц только для чтения, которые не требуют возврата на сервер или поддержки такого состояния.

Более эффективный подход Ч выборочное отключение состояния отобра жения серверных элементов управления. Чтобы отключить состояние ото бражения для индивидуального элемента управления, установите его свойство EnableViewState в false, например:

При разработке страницы вы можете следить за объемом, занимаемым ее состоянием отображения, включив трассировку для страницы: при свойте атрибуту trace директивы @Page значение true и проверяйте значе ние в столбце дерева элементов управления (рис. 2).

Tree System Web We Web.UI stem stem data _ System System Рис. 2. Дерево элементов управления Трассировщик не показывает суммарную цифру, но позволяет получить довольно точное представление о состояния отображения для от элементов управления. Страница на рис. 2 содержит лишь отно сительно простой элемент управления DataGrid. Как видите, львиную долю состояния отображения занимают данные ячеек сетки. В частности, элемент управления TableCell сохраняет в состоянии отображения всю информацию, связанную с UI, включая введенный в ячейку текст, ее ши рину и высоту, а также стиля.

В противоположность тому, что думают многие серверный элемент управления DataGrid не хранит в состоянии отображения содер жимое источника данных. На самом деле DataGrid кэширует в состоянии отображения почти все свои открытые свойства, но объем памяти, необхо димой для этого, никак не связан с источником данных. Однако DataGrid использует дочерние элементы управления, например TableCell, и они хра нят свой текст и сведения о стиле форматирования в состоянии отображе ния. Текст, отображаемый в является подмножеством источника данных DataGrid.

отображения На рис. 3 показана переработанная версия с рис. 2. Я добавил кнопку на клиентской стороне, при щелчке которой извлекается строка состояния отображения и ее длина, для чего достаточно про стейшего кода на JavaScript:

"V :

i, internet Х у Moreno Antonio Moreno the Horn Thomas Hardy snabbkbp Order See Moos Representative Marketing Manager Comidas Owner Bon app' Laurence Owner done j Рис. З. Извлечение строки из ViewState Программирование без использования состояния отображения Как уже говорилось, состояние отображения Ч это состояние страницы и всех ее элементов непосредственно перед рендерингом в HTML. При воз врате страницы на сервер состояние отображения извлекается из скрыто го поля, десериализуется и используется для инициализации страницы и размещенных на ней серверных элементов управления. Но это лишь пол дела.

После загрузки состояния отображения страница считывает присланную клиентом информацию через объект Request и заменяет полученными зна чениями большинство параметров серверных элементов управления.

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

Рассмотрим типичный случай. имеется страница с серверным элементом управления текстовое поле. Ожидается, что при возврате страницы на сервер в текстовое поле будет автоматически записано значе ние, введенное на клиенте. Для поддержки этой более чем обычной функ циональности состояние отображения не требуется. А теперь возьмем страницу, показанную на рис. Эта страница требует использования со стояния отображения, хотя оно отключено. Причина кроется в наличии двух серверных элементов управления (TextBox и чьи ключе вые свойства обновляются значениями, вводимыми пользователем. Эти данные заменяют любые значения, заданные в состоянии отображения.

Короче говоря, чтобы просто сохранять значения свойств вроде Text или Checked, можно обойтись без состояния отображения.

Рис. 4. Страница, требующая состояния отображения, хотя оно отключено sender, "false" /> /> При инициализации элемента управления все его свойства, объявленные как атрибуты в тэгах автоматически получают значения по умолчанию. Если значения этих свойств не будут меняться в течение дан ного сеанса, здесь тоже можно обойтись без состояния отображения. Если так, то когда же оно действительно нужно?

Предположим, что значение текстового поля может изменить лишь поль зователь с определенными привилегиями. Для этого можно объявить тек в gg стовое поле только для чтения, а затем отключить соответствующий атри бут при первой загрузке страницы и после проверки удостоверений поль зователя (рис. 5).

Рис. 5. Поле, доступное только чтения your /> При таком стиле программирования неизбежно получается код, использу ющий состояние отображения. Он будет нормально работать только при включенном состоянии отображении. Попробуйте присвоить атрибуту значение false и загрузите страницу еще раз. При обработ ке события страницы создается экземпляр текстового поля, как объявлено в разметке страницы, т. е. со свойством ReadOnly, равным Когда страница обрабатывается в первый раз (в этом случае IsPostBack возвращает false), код переключает атрибут в соответ ствии с привилегиями пользователя. Пока все хорошо.

Код на рис. 5 зависит от состояния отображения, так как предполагает, что после первого обращения к странице исполняющая среда запомнит все настройки. Но это не так, если состояние отображения отключено. Теперь, поскольку возвращает true, обработчик не сумеет модифицировать свойство Readonly текстового поля, Применив альтерна тивный стиль программирования, можно получить аналогичную функци ональность без состояния отображения, сэкономив по 40 байтов HTML кода на каждом экземпляре элемента управления TextBox. Ясно, что чем больше текстовых полей, тем заметнее экономия. Как видно из рис. 6, до статочно внести небольшие изменения в код, чтобы добиться той же фун кциональности без состояния отображения.

Рис. 6. Текстовое поле без void if return } void -, your /> В одних случаях отключение отображения не влияет на работу страницы, в других Ч придется внести в код небольшие изменения, чтобы гарантировать корректную инициализацию свойств всех элементов управ ления, Как правило, без состояния отображения можно если аналогичные данные можно получить от клиента или от исполняющей среды (например при наличии у пользователя привилегий). И напротив, без состояния отображения трудно обойтись, если соответствующие дан ные нельзя извлечь динамически. Так, контролировать порядок сортиров ки элемента управления DataGrid с прокруткой можно лишь при его кэ шировании в состоянии отображения.

Мой опыт говорит, что в принципе любую комбинацию стандартных эле ментов управления ASP.NET можно приспособить для работы на страни цах с отключенным состоянием отображения. Чем больше вы используе те нестандартных элементов управления (собственных и от сторонних поставщиков), тем больше проблем создает отключение состояния отобра жения. Имейте это в виду, собираясь писать собственные элементы управ ления ASP.NET, и не перегружайте состояние отображения сверх меры.

Состояние в ASP.NE7 состояния отображения на сервере Я уже говорил, что состояние отображения хранится в скрытом поле на клиенте. Однако это вариант хранения по умолчанию. Посмотрим, как сохранить состояние отображения файле на Web-сервере.

Для создания альтернативной схемы хранения состояния отображения нужно извлечь строку, которую ASP.NET хранит в скрытом поле. Затем ее можно сохранить в файле на сервере или в таблице базы данных и считы вать всякий раз, когда выполняется обработка страницы. Но знайте, что у этого подхода есть не только достоинства, но и недостатки.

Плохая новость в том, что строка состояния отображения хранится в ко дировке и в таком виде недоступна коду страницы. А хорошая класс, который используется Framework для и десери состояния отображения, является открытым (а не внутренним) и, следовательно, может быть вызван из пользовательского приложения.

Но пока этот класс документирован лишь частично.

Программный интерфейс класса LosFormatter довольно прост и состоит всего из двух открытых методов: Serialize и Deserialize. Метод Serialize за писывает конечное представление состояния отображения (в кодировке Base64) в объект Stream или TextWriter:

public void object viewState);

public void output, object viewState);

Метод Deserialize создает объект StateBag из потоковых данных, объекта TextReader или строки в кодировке Base64:

public object stream);

public object input);

public object Deserialize(string input);

LosFormatter Ч точка входа во внутренний механизм состояния отображе ния;

при использовании этого класса все должно работать как обычно.

Кроме того, у класса LosFormatter есть свойство только для чтения под названием которое разрешает шифрование/дешиф рование К этой переменной нельзя получить программный доступ, так как она помечена как внутренняя. Это означает, что с ней мо гут лишь классы, размещенные в той же сборке. Но поскольку я просто подключаю свой код к конвейеру ASP.NET, передающему данные состояния отображения, я могу управлять аутентификацией машины, ис пользуя высокоуровневые средства, описанные ранее.

98 Microsoft К счастью, класс Page поддерживает разные схемы хранения. У него есть пара виртуальных методов, используемых исполняющей сре дой для сериализации и состояния отображения. Метод восстанавливает состояние отобра жения в начале жизненного цикла страницы, а его антипод Persistence Medium сохраняет это состояние непосредственно перед рен дерингом страницы:

protected virtual void protected virtual object Переопределив оба метода, можно считывать и записывать состояние ото бражения практически куда угодно, а не только в скрытое поле (замещать эти методы по отдельности нельзя Ч только оба сразу). Поскольку они определены как единственный способ заместить их Ч со здать новый класс, производный от Page. Следующий код дает представ ление о том, как по умолчанию работает загружающий состояние отображения:

string = = new object viewStateBag = Заметьте, что объект, возвращаемый LosFormatter-методом Deserialize, не является объектом StateBag, с: которым реально работает программист.

Deserialize возвращает лишь один из промежуточных внутренних объек тов, упомянутых мной ранее. Я хочу создать страницу с такой структурой:

public>

protected void object viewStateBag) { string file = = new LosFormatter = new Состояние отображения в В этом фрагменте кода состояние отображения сохраняется в файле на сервере. Внеся минимальные можно сохранять его и в базе данных. Но как выбрать такое имя файла, которое не создавало бы конф ликтов? Состояние отображения специфично для запроса страницы в рам ках конкретного сеанса. Поэтому идентификатор сеанса и запроса Ч те самые уникальные данные, с помощью которых можно связать запрос с нужным файлом. В качестве альтернативы вы могли бы присваивать фай лам с состоянием отображения имена, генерируемые случайным образом, и сохранять эти имена в собственном скрытом поле на странице. Однако тогда скрытое поле придется создать вручную Ч использовать поле _VIEWSTATE нельзя, так как переопределяя методы, вы изменяете внутреннюю процедуру, которая его создает.

Функция GetFileName в только что показанном коде назначает файлам имена по следующему шаблону:

Некоторые файлы, созданные этой функцией во временном каталоге, по казаны на рис. 7. Заметьте: чтобы ASP.NET-приложение могло создать локальный файл, вы должны наделить учетную запись ASP.NET особыми разрешениями в отношении файла или каталога. Для хранения всех фай лов с состоянием отображения я бы посоветовал создать новый подката лог. Удаление файлов для сеансов, срок действия которых истек, чуть сложнее. Для этого можно было бы создать службу Windows NT, периоди чески проверяющую временный каталог и удаляющую ненужные файлы.

Это лучше, чем простое удаление файлов при обработке события Ses sion OnEnd, tec* KB File Рис. 7. Файлы с состоянием отображения во временном каталоге Метод определяет имя файла, из которого нужно считать данные, извлекает строку в кодировке Base64 и вызывает из класса метод, данные (рис. 8).

ASP.NET Рис. 8.

object object viewStateBag;

string = new = new try { = I { throw View State viewStateBag;

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

Но знайте, что идентификаторы сеансов (как и любой механизм состоя ний) уязвимы перед атаками с повторением пакетов (replay attacks) и средствами анализа пакетов, поэтому здесь тоже нужно остерегаться неко торых подводных камней, описанных выше. И вновь Ч лучшее сред ство защиты данных при пересылке. Кроме того, вы можете сохранять файлы вне пространства Web-приложения и назначать им случайные име на. А реальное имя файла можно закодировать и записать в скрытое поле.

Заключение Состояние отображения Ч ключевой элемент по скольку это главный механизм сохранения состояния серверных Web-эле ментов управления на Всякий раз, когда страница возвращает ся на сервер, ее состояние отображения восстанавливается, обновляется текущими значениями параметров формы и используется для обработки события возврата формы на сервер (postback event). Обычно состояние отображение представляет собой строку в кодировке Base64, хранимую в скрытом поле _ VIEWSTATE. Состояние отображения не кэшируется на клиенте, а передается от клиента к серверу и обрат но, что снижает производительность и угрожает безопасности приложе ния. Но состояние отображения можно хранить на сервере, для чего потре буется минимум кода. За это придется расплачиваться издержками на об Состояние отображения в ASP.NET ращение к дисковому файлу или базе данных, зато страницы похудеют и будут более защищенными. Хотя я рассматривал постоянное хранилище на сервере (в файле или базе данных), ничто не использовать для этой цели объект Cache, который позволит хранить данные на сервере и обеспечит высокое быстродействие.

Дино Эспозито Esposito) Ч консультант и преподаватель из Рима.

Автор книг Building Web Solutions with and ADO.NET и Applied XML Programming for (обе выпущены Microsoft Press в 2002 г.). Большую часть своего времени тратит на преподавание ASP.NET. С ним можно свя заться по адресу dinoe@wintellect.com.

Стивен Смит ASP.NET Девять способов сохранения состояний в ASP.NET-приложениях В ASP.NET много способов сохранения данных между запросами. Вы можете использовать объекты Application, и Cache, cookie, скрытые поля и т. д. в каких случаях следует применять тот или иной способ, порой очень трудно. Автор знакомит с вышеперечисленными способами и дает рекомендации по их применению. Хотя многие из этих способов и в классической ASP, с появлением Framework принципы их использования изменились. Поэтому того, что вы знали о сохранении состояний в ASP, в ASP.NET уже недостаточно.

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

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

Чтобы сделать правильный выбор, нужно учесть три критерия.

Х Кто получатель данных?

Х Как долго нужно хранить данные?

Х Каков объем набора данных?

Публиковалось в Редакция. 2003. № 4 (апрель). Ч Прим. изд.

способов сохранения состояний в Ответы на эти вопросы позволят вам выбрать оптимальный вариант со хранения данных между запросами в приложении ASP.NET. В табл. 1 пе речислены механизмы управления состоянием и описано, в каких случа ях их следует применять. Б ASP.NET введено три новых объекта (Cache, Context, и конфигурационный файл Кроме того, остались доступными механизмы классической ASP, например объекты Application, Cookie, и Session, а также передача данных на сер вер через скрытое поле при возврате формы. Заметьте, что старые контей неры, применявшиеся в ASP, теперь используются в других ситуациях, поэтому опытным придется часть своих навыков работы с привычными объектами.

Объект Application Попробуем охарактеризовать этот объект с учетом критериев, о которых я уже говорил. Кто получатель данных? Доступ к объекту Application нужен всем пользователям. Как долго нужно хранить данные? Этот объект позво ляет хранить данные вечно, т. е. в течение срока жизни приложения. Ка ков объем набора данных? Он может быть любым, так как будет существовать не более одной копии этих данных.

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

В ASP объект Application был идеален для хранения данных, редко или вообще не изменявшихся в течение жизни приложения. Типичный пример таких данных Ч строки подключения, но в ASP.NET подобные конфигу рационные данные рекомендуется хранить в файле Web.config. Если вы используете объект Application, то должны учесть, что любые операции записи в него должны выполняться либо в его обработчике Applicati либо внутри раздела Применение Applicati обязательно, так как гарантирует корректную запись данных в объект Application;

однако это требует запросов к объекту, что существенно снижает производительность приложения, становясь его лузким местом. Код, показанный на рис. 1, демонстрирует, как пользо ваться объектом Application. Этот пример включает Web-форму и файл отделенного кода (code-behind file);

результат его работы представлен на рис. 2.

Табл. 1. Объекты Ч контейнеры данных в ASP.NET.

Л Способ сохранения Получатель данных Срок хранения Объем данных Application Все пользователи До приложения Практически любой, так как будет только одна копия этих Cookie Один Произвольный (от нескольких секунд Простые данные объема до нескольких месяцев и даже лет) условии, что не удаляет свои cookie Передача формы Один До следующего Практически любой данные передаются таким образом данные можно исполь- между клиентом и сервером с каждой зовать многократно, между страницей Ч ОдИН До или одна группа емые таким образом можно пользователей использовать многократно, между несколькими запросами) Один пользователь Равен длительности сеанса Любой, но лучше свести его к минимуму, пользователя плюс поскольку для каждого пользователя ожидания (обычно 20 мин) создается отдельный экземпляр объекта для хранения данных Cache Один пользователь Произвольный Данные любого объема и сложности или одна группа Context Один пользователь Равен сроку жизни Можно хранить но этим текущего редко пользуются, так как для каждого запроса обычно создается новый Context ViewState Один сроку Web-формы Минимальный;

как и в случае передачи формы, ViewState передается между клиентом и вместе со страницей Все пользователи До модификации Можно хранить значительный файл файла данных, обычно организованных в виде набора коротких строк или XML-структур Девять способов состояний Рис, 1. Обращение к объекту Application в ASP.NET Application.aspx is required."

is required," /> private void e) >;

"The value of " см. след. стр.

Microsoft ASP.NET Рис. 1. Обращение к объекту Application в ASP.NET Application foo bar hello world Collection Headers Connection Accept Accept deflate Encoding Accept Рис. 2. Содержимое объекта Application Обратите внимание, что содержимое объекта Application представлено на рис. 2 как трассировочный вывод. Трассировка Ч действительно велико лепный инструмент отладки, но не исключено, что однажды в вашем ра бочем окажется страница с трассировкой. И тог да посторонние запросто увидеть конфиденциальные что явно нежелательно. Это главная причина, по которой объект Application больше не рекомендуется в хранилища конфиденциальных дан ных вроде строк подключения.

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

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

Наконец, cookie записываются на пользовательскую машину как обычные текстовые файлы, поэтому не следует хранить в cookie конфиденциальные данные, предварительно не зашифровав их.

В cookie может быть как единственное значение, так и набор пар лимя значение. На рис. 3 показаны примеры содержимого cookie обоих типов, полученные при помощи встроенного трассировщика ASP.NET.

ями cookie можно манипулировать через наборы и Res (рис. 4).

3 View Tods Help I leaders Рис. З. Примеры cookie с одним и несколькими значениями Рис. 4. Доступ к cookie в ASP.NET aspx.cs // Установка <или значений) cookie см. след. стр.

108 Microsoft ASP.NET Рис. 4. к cookie в ASP.NET null) = new cookie > 0) = // завтра // Выборка из cookie if Request.

value of + * is + else = "The value of the " + is + + with key in Keys) key + - * I // Присвоить null cookie и установить // срок действия, который Text].

назад Передача формы и скрытое поле на форме Данные формы нужны конкретному пользователю, а время их хранения варьируется между сроками текущего запроса и приложения. Раз мер таких данных может быть любым;

они пересылаются при каж дой передаче формы клиенту и обратно на сервер.

Это был общепринятый способ сохранения состояния в ях Ч особенно при наличии многостраничных форм. Однако в ASP.NET такой прием Ч редкость, так как Web-элементы и автоматичес Девять сохранения состояний в решают эту задачу при использовании модели возврата формы на сер вер (postback). ASP.NET реализует этот подход через о котором поговорим позже. Доступ к значениям формы, пересылаемым POST, при набора объекта На рис. показан код двух одна из которых устанавливает иден тификатор пользователя, после чего он записывается в скрытое поле. При последующих запросах к любой из страниц идентификатор сохраняется, если страницы связаны друг с другом через кнопки Submit.

Рис, 5. Сохранение данных в ASP.NET помощью скрытых Label fltinat* "server" Hidden Variable:

flunat="server"x/asp:textboxx^S>

to private см. след. стр.

Microsoft Рис. 5. Сохранение данных в // или от // набор else // false;

* // чтобы // установить } { // Скрыть чтобы установить = false;

* set to + + to void sender, e?

см, след, стр.

Девять способов сохранения состояний в Рис, 5. Сохранение данных в ASP.NET I* * В ASP.NET на странице может быть только одна серверная форма, причем эта форма должна возвращать данные сама себе (клиентские формы по прежнему используются без ограничений). Одна из основных причин, по которой скрытые поля форм больше не применяются для передачи данных в приложениях, построенных на основе Framework, состоит в что все элементы управления на этой платформе умеют автоматически сохранять свое состояние через просто инкапсули рует все операции, необходимые для установки и получения значений скрытых полей.) Данные, хранящиеся в объекте QueryString, нужны индивидуальному пользователю. В зависимости от архитектуры приложения эти данные могут жить не дольше отдельного запроса, или существовать на протяже нии всего сеанса работы с приложением. Объем этих данных обычно не превышает 1 Кб. Содержимое объекта передается в URL и видно пользователю. Отсюда ясно, что при таком способе информацию, которую нужно скрыть от посторонних глаз, и данные, позволяющие кон тролировать приложение, следует шифровать.

QueryString Ч прекрасное средство для обмена информацией между Web формами в ASP.NET. Если, например, ваша форма содержит элемент уп равления DataGrid со списком товаров, где должны быть гиперссылки на страницы с подробным описанием каждого товара, то идеальный вариант применения QueryString Ч включать идентификатор товара (скажем, в QueryString соответствующей ссылки на стра ницу с детальными сведениями. Другое преимущество QueryString в том, что он позволяет передавать состояние страницы через URL.

Как уже говорилось, этим способом не стоит передавать конфиденциаль ную информацию и любые переменные, которые следует скрыть от поль зователя, если только они не защищаются шифрованием. Также учтите, что символы, недопустимые в URL, надо кодировать с помощью Ser ver.UrlEncode, как показано рис. 6. Если вы имеете дело с единственной AS для сохранения состояния лучше выбрать а не Для хранения состояний рекомендует ся использовать Cookie, Session и Cache.

Рис. 6. Передача в через QueryString

S Variable:

fluBat=*" is button fetittonx/td> fiinatл"server"

способов в Рис. 6. Передача данных через "The values of + in + + " * private void e) key in flequeet.Ou&ryString.Keys) I url key * + + Server.

Объект Session Сеансовые данные специфичны для конкретного пользователя. Они суще пока пользователь продолжает выдавать запросы, плюс небольшой интервал впоследствии (как правило, 20 минут). Объект Session способен хранить значительные объемы данных, но лучше сводить их к минимуму, если с приложением будут работать несколько сотен пользователей или больше.

К сожалению, в классической ASP объект Session снискал себе дурную репутацию, поскольку он привязывает приложение к конкретному компь ютеру, препятствуя масштабированию этого приложения за счет механиз мов кластеризации и Web-ферм. В ASP.NET эта проблема не столь серьез на, поскольку место хранения сеансовых данных можно легко изменить:

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

Microsoft ASP.NET Объект Session прост в использовании, а его синтаксис не отличается от такового в классической ASP. Однако применение Session Ч не самый эф фективный способ хранения пользовательских данных, поскольку этот объект остается в памяти еще некоторое время после завершения работы пользователя с приложением, что препятствует масштабированию на сильно загруженных сайтах. Для хранения объемов данных луч ше подходят другие объекты, например которые обеспечивают бо лее эффективный контроль за освобождением памяти. Кроме того, сеансо вые переменные в ASP.NET по умолчанию полагаются на cookie. Поэтому, если cookie отключены или браузер их не поддерживает, сохранение сеан совых данных окажется Тем не менее ASP.NET позволяет сконфигурировать поддержку сеансов, не использующих cookie (cookie free sessions). Объект Session идеален для сохранения небольшого объема данных, специфичных для пользователя, только на время его сеанса. Вот пример, демонстрирующий запись/чтение значений в объекте Session:

private sender, e) { { // Записать значение в = // Считать и вывести только что записанное значение = "The value of + in the Session object is + + Эта Web-форма практически идентична той, которая была показана при демонстрации объекта Application. В этом случае тоже можно просматри вать содержимое набора Session, включив трассировку страницы.

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

Девять способов сохранения в Сеансовые переменные в ASP.NET можно сконфигурировать с элемента sessionState в файле или Атрибуты, поддерживаемые этим элементом, перечислены в табл. 2.

2. Атрибуты элемента Атрибут Значения Описание mode Отключает сеансовые переменные To что и в классической ASP. Предлага ется по умолчанию. Сеансовые переменные хранятся в локальной памяти Web-сервера.

Это значение позволяет достичь макси мальной производительности, но не дает возможность использовать кластеры StateServer Сеансовые переменные хранятся в памяти другого сервера SqlServer Сеансовые переменные хранятся в базе данных SQL Server True Включает поддержку сеансов без cookie.

cookieless Идентификатор сеанса автоматически передается не через cookie, а через во всех относительных URL URLs) Значение по умолчанию. Сеансы использу ют cookie Таймаут сеанса в минутах (по умолчанию Ч timeout 20 минут) Строка подключения для сеансов с state Connection String Строка подключения для сеансов с Вот пример соответствующей настройки через Web.config:

/> Новые контейнеры состояний в ASP.NET Как уже говорилось, в ASP.NET появилось несколько новых со хранения данных во время обработки и в интервалах между ними. Эти способы предоставляют механизмы гораздо более тонкого уп равления тем, как сохраняется информация о состоянии. Область их дей ствия может быть сужена до уровня отдельного запроса (посредством объекта Context) или расширена до уровня Web-сервера и всех приложе Microsoft ний, работающих на нем (через файл Во многих случаях одни и те же данные можно несколькими способами, поэтому, чтобы выбрать подходящий, задайте себе те вопросы, которые я привел в начале статьи, и ответьте на них, используя соответствующие справочные материалы.

Объект Cache Объект Cache хранит данные, специфичные для одного пользователя, группы или даже всех Эти данные на протяжении обработки нескольких запросов и могут храниться достаточно долго, но до перезапуска приложения;

кроме они могут считаться устаревшими по истечении заданного срока действия или в результате других событий.

Объект Cache способен эффективно хранить как значительные, так и ма лые объемы данных.

Cache Ч один из самых потрясающих объектов в ASP.NET. Благодаря не вероятной гибкости, и производительности он лучше подходит для хранения данных в приложениях ASP.NET, чем объекты Application или Session. Полное описание способов применения объекта Cache (декларативного и программного) выходит за рамки этой статьи, и здесь я лишь еще раз подчеркну, что это универсальный объект. Как и дру гие объекты-наборы, он просто хранит пары но, опреде лив специфичный для какого-либо пользователя ключ, кэшируемые дан ные можно сделать специфичными для этого пользователя. Аналогичным образом можно кэшировать несколько наборов связанных данных, напри мер, описания автомобилей, применяя ключи вроде или Для данных, помещаемых в Cache, можно задать срок дей ствия Ч абсолютный, скользящий (sliding) или зависящий от изменений в каком-либо файле. Кроме того, вы можете реализовать функцию обрат ного вызова, запускаемую всякий раз, когда какой-то элемент удаляется из кэша. Этот механизм очень удобен, так как позволяет проверять, есть ли обновленные данные, и, если их нет (или источник данных недоступен), возвращать элемент, срок действия которого только что истек, обратно в кэш.

Для записи данных в кэш и обращения к данным приме няется синтаксис, аналогичный ранее описанному. Но, помимо стандарт ного метода-индексатора (indexer method), для доступа к набору объекта Cache предусмотрен ряд других методов, предоставляющих дополнитель ные возможности в управлении кэшированными данными. Наиболее по пулярный из них Ч метод Insert, который поддерживает ряд перегружен ных версий, позволяющих зависимости, (периоды ожи дания), приоритет и функции обратного вызова для дан ных. Вот несколько простых примеров:

Девять способов сохранения состояний в ASP.NET-приложениях // Записать элемент в кэш = // Считать из кэша // Определить срок элемента в 10 секунд и записать его в кэш null, Одна из самых интересных возможностей объекта Cache Ч его способ ность выполнять функции обратного вызова по истечении срока действия элемента. Эта возможность реализуется на основе делега тов и указателей на функции, обсуждение которых выходит за рамки моей статьи. К счастью, при наличии образца, показывающего, как работает этот механизм, вы сможете применять его в своих приложениях, не вникая во все тонкости делегатов, Ч просто перенесите нужный код методом копи рования и вставки. Такой механизм полезен во многих ситуациях. Чаще всего его применяют для возврата в кэш текущих данных по истечении срока их действия, а также для восстановления в кэше прежних данных, если источник, используемый для заполнения кэша, окажется недоступным.

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

Код на рис. 7 демонстрирует важную концепцию обратных вызовов и яв ляется шаблоном, на основе которого можно создавать более функцио нальные процедуры обратного вызова в реальных приложениях.

Рис. 7. Пример использования обратных при кэшировании private e) string data = // Проверить, есть ни данные в // Если кэш данные data = Создать вызова " * см. след. стр.

Рис. 7. Пример использования...

ration, { * private void Reason reason) Создать вызова new Mow, Важно отметить, что обработчик на рис. 7 определяет, надо ли использовать данные, по шаблону. Рекомендуется всегда применять такой шаблон при работе с элементами в кэше. Здесь с помо щью оператора if текущее кэша проверяется на null (ключ данных лучше хранить в переменной, поскольку вы буде те неоднократно ссылаться на него). Если содержимое соответствует null, вы должны получить данные из источника и поместить в кэш;

в ином слу чае возвращайте данные из кэша. Если для доступа к данным применяет ся очень сложная логика, вынесите этот оператор if в отдельную функцию.

На самом деле функциональность объекта Cache куда шире, чем я мог здесь рассказать. Это один из самых мощных объектов в ASP.NET, и я на стоятельно советую детально разобраться в нем.

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

Девять способов в Контейнер Context (доступный через объект Page или через служит для хранения передаваемых между различными HTTP-модулями и ками Кроме того, он позволяет хранить сведения, относя к запросу в целом. Так, портал записывает часть конфигу рационной информации в этот объект при выполнении обработчика cation_BeginRequest, определенного в Заметьте, что это приме нимо только к текущему запросу;

если вам нужно, чтобы данные сохраня лись до следующего запроса, подумайте об использовании Для записи и чтения данных из набора Context применяется синтаксис, уже описанный для других объектов-наборов, таких как Application, Sessi on и Cache. Вот пара простых примеров:

// Записать в объект Context = // Считать объекта Context Объект ViewState ViewState хранит информацию о состоянии для отдельного пользователя, пока тот работает с данной ASPX-страницей. Контейнер ViewState спосо бен хранить значительные объемы данных, однако вы должны вниматель но следить за их размером: чем он больше, тем медленнее выполняются запросы и дольше время ожидания ответа.

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

Проще всего определить размер ViewState для каждого элемента управле ния на странице так: включите трассировку и проанализируйте ее резуль таты, чтобы выяснить вклад каждого элемента управления в общий размер состояния отображения. Если какой-то элемент управления не требует сохранения данных между возвратами страницы, отключите его состояние отображения, установив View State в false. Чтобы узнать суммарный размер ViewState для данной просмотрите ее исход ный HTML-код в браузере и исследуйте скрытое поле VIEWSTATE.

Содержимое этого поля кодируется по основанию чтобы предотв ратить его просмотр и модификацию. ViewState можно отключить и для всей страницы, добавив к директиве В типичных Web-формах манипулировать состоянием отображения на прямую не требуется, но если вы создаете нестандартные Web-элементы управления, то должны знать, как оно работает, и реализовать его по ана логии с тем, как это сделано в стандартных Web-элементах управления, поставляемых с ASP.NET. Синтаксис чтения и записи значений в состоя ние отображения Ч тот же, что и для объектов-наборов:

// Записать элемент во ViewState = // Считать элемент ViewState Возможно, что при разработке собственных Web-элементов вы захотите задействовать в них преимущества состояния отображения. Это легко сде лать на уровне свойств. На рис. 8 показано, как сохранить значение свой ства PersonName нестандартного элемента управления в состоянии ото бражения и впоследствии извлечь его для передачи методу Render этого элемента.

Рис. 8. во ViewState С public string I string s return ? : s);

set * protected override void " + Девять способов в Файлы Web.config и Информация в этих файлах доступна всем пользователям Данные, помещаемые в Web.config, существуют на протяжении срока жиз ни приложения;

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

Помимо различных объектов-наборов, в ASP.NET введен целый набор конфигурационных XML-файлов. Они служат для управления параметра ми приложений и даже сервера. У каждого приложения есть файл Web.con fig, определяющий многие из его свойств, а у каждого сервера Ч файл fig, расположенный в его системном каталоге и определяющий базовую конфигурацию всех приложений. Параметры, заданные в этом файле, считаются параметрами по умолчанию. Они используются, если другие файлы или настройки не переопределяют их. Кроме сведений о конфигурации, в этих файлах могут храниться данные, необходимые при ложению (или, как в случае Machine.config, нескольким приложениям).

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

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

Параметры, специфичные приложения /> Х Чтобы получить доступ к этим значениям из приложения ASP.NET, ис пользуйте набор Configuration Settings из пространства имен 122 Microsoft figuration. Вот простой пример, демонстрирующий чтение строки подклю чения, показанной в предыдущем примере:

using String = Добавление ссылки на имен сокраща ет объем кода, необходимого для обращения к этим значениям. Посколь ку изменение или перезапуск прило жения, эти файлы обычно модифицирует только администратор сервера.

Отсюда что Web.config и Machine.config удобны для хранения неизменяемых данных, а данные, которые могут быть модифицированы приложением, лучше хранить другом месте.

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

Исходный код для этой статьи можно скачать по ссылке в разделе за апрель.

Стивен А. Смит A. Smith) Ч президент ASPAIfiance.com, LLC популярного в сообществе разработчиков ASP и ASP.NET. Ведет учебные курсы по ASP.NET в Ltd. Соавтор книги ASP.NET Developer's Cookbook (SAMS, 2003). С ним можно связаться по адресу Джордж ASP Отделенный код в Автор рассказывает о модели отделенного кода model) в которая позволяет отделить код визуализации, обычно помещае мый в от логики выполнения сценариев, которая выносится в какой-либо модуль и пишется на любом языке программирования, поддер живаемом CLR. В качестве примера автор показывает, как разрабатывать с отделенным кодом на Managed созда вать код.

В середине 90-х что СОМ решит все проблемы разработки ком понентного ПО (т. е. позволит распределять и интегрировать приложе ния). Но примерно в 1997 г. фундамент начал давать трещины. В частно сти, не оправдались ожидания, что СОМ устранит сложности с управле нием версиями. Были выявлены и другие проблемы, в первую очередь несоответствие типов данных, доступных в коде, информации о типах, предоставляемой СОМ. Хотя одной из главных причин создания платфор мы Microsoft было стремление упорядочить подходы к Web-програм мированию, преследовалась и цель решить проблемы СОМ. В итоге появи лась общеязыковая исполняющая среда language runtime, CLR).

CLR Ч потрясающая вещь! В ней под одной крышей собрано все лучшее из мира компонентного ПО: сбор мусора, поддержка интерфейсов и насто ящая совместимость на уровне двоичного кода. Исчезли странности, связанные с переменными произвольного типа (variants) (или IDispatch) и интегрированной информацией о типах. Список дос * Публиковалось в MSDN Magazine/Русская Редакция. 2002. № 2 (август). Ч Прим. изд.

124 ASP.NET ТОИНСТБ CLR этим не но и перечисленных хватит, что бы оценить CLR.

Если вам доводилось работать с классическим вы, несомненно, зна комы с некоторыми из его недостатков Ч особенно с проблемами управ ления версиями и с ограничениями, налагаемыми IDispatch. Так, если ASP-страница должна сценарии, вы можете использовать только типы VARIANT. Еще одной проблемой является то, что код сцена риев и код визуализации страницы зачастую смешиваются. Многие стра ницы в классическом ASP представляют собой малопонятную смесь HTML и блоков сценария. ASP.NET решает эти проблемы на основе модели от деленного кода (code-behind model), поддерживаемой CLR.

Модель отделенного кода позволяет отделить код визуализации (presen tation code), обычно помещаемый в ASPX-файл, от логики выполнения, которая выносится в какой-то (в файл исходного кода на С# или Visual Basic либо в сборку). Тот, кто уже занимался разработкой на Visual Basic, вероятно, предпочтет синтаксис Visual Basic. А если есть же лание попробовать нечто новое, то язык предоставит вам ясную и гиб кую парадигму разработки модулей такого кода. Хотя синтаксис С# удо бен опытным разработчикам на C++, он все же отличается от C++, и к его особенностям придется привыкать. Если вы знаете C++ и у вас нет жела ния немедленно изучать синтаксис нового языка, есть третий вариант: ис пользовать C++ для написания своего отделенного кода. В этой статье я покажу, как с помощью Managed C++ можно разрабатывать ASPX-стра ницы с отделенным кодом.

Managed C++ Microsoft Ч лидер в разработке ПО, обладающего обратной совместимос тью. Эта компания давно поняла, что самый эффективный способ заполу чить максимум пользователей для своих программных продуктов Ч про кладывать мостики между текущими и новыми версиями, На C++ напи саны тонны кода, и очень многие разработчики чувствуют себя в C++ по настоящему комфортно. У программных продуктов есть нечто вроде пери ода полураспада: они никогда не исчезают в один момент. Действительно, трудно сразу отказаться от какого-то ПО. И платформа не стала бы столь популярной, если бы требовала от разработчиков и компаний отка за от всего, что они наработали за многие годы. Поэтому Microsoft доба вила в C++ расширения, которые позволяют создавать код, выполняемый в среде Если вы опытный программист на C++, значит, привыкли проверять, что бы для каждого оператора new вызывался свой оператор delete, и пишете Отделенный код в ASPX-файлах отдельно от исходного Кроме того, вас, раз дражают все эти ошибки из-за ссылок по недопустимому указателю или из-за того, что вы забыли освободить какую-то область памяти. Применяя новые расширения Managed C++ в Visual C++ вы получите компи лятор, умеющий генерировать сборки под CLR. Классы, помеченные как использующие эти расширения, будут включены в систему сбора мусора Ч как и любой другой управляемый код. Вы сможете создавать экземпляры и не об их удалении Ч за вас это сделает исполняющая да. Кроме того, компилятор C++ будет автоматически генерировать ин формацию о типах (метаданные) для сборки, и писать отдельный IDL код не понадобится. Наконец, вы избавитесь от трудноуловимых сбоев при ссылках по недопустимым указателям: в таких случаях будет генери ровать предсказуемые исключения.

Как оказалось, писать отделенный код с использованием Managed C++ не так уж и сложно. Просто слишком мало примеров удачного применения C++ в этой области. Вот поэтому я и хочу рассмотреть весь процесс созда ния страницы ASP.NET с отделенным кодом, написанным с применением Managed C++.

Начнем с Она будет отображать список преимуществ ASP.NET, запрашивать имя пользователя, а затем предлагать выбрать луч шую функциональность и отправить ответ на сервер. Все визуальные эле менты я реализую в коде ASPX-страницы, все логические Ч в отделенном коде (рис. 1).

Рис. 1. ASPX-страница Ч хост для отделенного С++-кода Раде ASP.NET Entry" name см. след. стр.

Microsoft ASP.NET Рис. 1. Ч хост для отделенного />
Label /> Директива Page в начале на рис. 1 указывает, что эта страница базируется на классе ASP.NET будет искать этот класс в одной из сборок, которые находятся в каталогах, прописанных в пути поиска. В данном случае я напишу класс используя Managed C++, и поме щу сборку в каталог виртуального каталога (Internet Information Services), в котором будет размещена Далее в ASPX-странице объявляется несколько серверных элементов управления: кнопка, надпись (метка), текстовое поле и раскрывающийся список. Заметьте, что все они помечены атрибутом Кроме того, обратите внимание, что в ASPX-коде имеется строка, откуда вызывается функция Этот метод реализуется в странице отделенного кода. возьмите на заметку, что с кнопкой связан обработчик события SubmitEntry. На рис. 2 показано, как выглядит эта Теперь добавим начинку, создав модуль с отделенным кодом.

Самый простой способ создать сборку Managed C++ Ч воспользоваться мастером в Visual Studio Выберите File | New j Project и среди шаб лонов Visual C++ Project укажите Managed C++>

Табл. 1. Файлы, сгенерированные AppWizard Файл Описание Глобальные атрибуты проекта в целом, в том числе описание сборки, версия и файл цифровой подписи (если вы его используете) Исходный код тела класса Определение элементов внутри сборки;

именно в этом файле объявляется и реализуется отделен ный код см. след. стр.

В коде автор по ошибке присвоил кнопке название вместо Submit Entry. Ч Отделенный код в ASPX-файлах Табл. 1. Файлы, сгенерированные Файл Описание ManagedCPPLibrary.PROJ Файл проекта Visual Studio Файл решения Visual Studio Используется для включения в исходный код стандартных заголовочных файлов (header files) и определений C++ STDAFX.CPP Используется для управления заголовками Edit View Links:

Favorite Features;

Separating presentation from execution Х Smooth data integration Х Garbage collection Х Faster execution Type your name here Hello George you selected Garbage collection Рис. 2. Страница с отделенным кодом Только что созданная библиотека Managed C++ пока бессодержательна.

Ее компиляция и компоновка дала бы пустую сборку. В нее нужно доба вить отделенный код. Как и в С# или Visual Basic класс такого кода должен наследовать от класса При этом вы должны позаботиться о том, чтобы сборка ссылалась на необходимые системные модули и пространства имен.

Если вы работаете с Visual Basic или С# в среде Visual Studio не забудьте установить в проекте ссылки на внешние сборки. Для этого откройте References из меню Visual Studio Программируя на C++, ссылки на внешние сборки можно установить директивой препроцессора C++. Кроме того, полезно объявить, какие пространства имен вы используете, чтобы не указывать область видимости при каждом объявлении. Вот как выглядят директивы для ссылки на сборки System и Web, а также определения пространств имен по умолчанию.

using namespace System;

using namespace using namespace using namespace using namespace using namespace using namespace Заметьте, что при объявлении используемых пространств имен соблюда ется стандартный в C++ синтаксис задания областей видимости. Цент ральное место в модуле отделенного кода занимает класс, производный от Рассмотрим его.

Класс отделенного кода Хотя исходный код, обслуживающий страницу с отделенным кодом (рис.

во многом напоминает обычный C++, в нем есть несколько существенных отличий. перед объявлением класса указан модификатор public. Ключевое слово public перед объявлением класса ManagedCWebPage означает, что весь класс становится видимым вне сбор ки. Это важно, так как потребуется доступ к классу Mana gedCWebPage.

3. Класс отделенного кода (Managed C++) namespace i public _ gc ManagedCWebPage Page { public:

Label* см. след. стр.

Отделенный код в Рис. 3. Класс отделенного кода C++) = str;

str execution" str * integration";

str * str * execution";

void о, e) String* str str * str you atr * { void I for i str 5- Microsoft Ключевой символ gc, предшествующий ключевому слову>

В остальном синтаксис выглядит вполне привычно. В ASPX-странице оп ределяются кнопка, раскрывающийся список, надпись и текстовое поле.

Программные эквиваленты этих элементов управления определяются как переменные-члены (в начале тела класса). Если вам приходилось програм мировать на С#, вы, наверное, удивляетесь, почему переменные-члены, представляющие элементы управления, объявлены в этом коде как указа тели. Дело в том, что C++ распознает управляемые типы, только если они объявлены как указатели. Вспомните: в отличие от синтаксиса синтак сис C++ поддерживает истинные указатели.

Класс Managed реализует два обработчика событий: один Ч для Load страницы, другой Ч для события (оно возни кает, когда пользователь нажимает кнопку Submit Entry). сра батывает всякий раз, когда клиент отправляет данные на сервер. У класса имеется свойство IsPostBack, позволяющее опреде лять, является сеанс новым или существующим, Если IsPostBack равно true, пользователь отправляет данные на сервер в рамках существующего сеанса. В ином случае это сеанс. SubmitEntry извлекает имя пользо вателя из текстового поля, а элемент Ч из раскрывающегося списка и присваивает соответствующее значение свойству Text элемента управления Label. Синтаксис каждого из этих методов похож на синтак сис, который вы увидели бы эквивалентном коде на С#. что параметры передаются как указатели, поскольку Object и управляемые типы.

Чтобы страница заработала, просто скомпилируйте сборку и поместите ее в каталог виртуального каталога, содержащего ASPX-код.

Заключение Если вы Ч опытный разработчик на ASP и привыкли писать СОМ-код, страницы, то CLR станет для вас глотком свежего возду ха. Любой код, выполняемый в автоматически согласует типы дан ных, порядок параметров в стеке и местонахождение сигнатур методов в коде (все это описывается метаданными). Так что все старые проблемы, для решения которых создавалась СОМ, исчезли.

Для создания кода, выполняемого в CLR, нужен лишь компилятор, спо собный генерировать (intermediate language), например С# или Visual Basic Большинство разработчиков, в настоящее время исполь Отделенный код в зующих Visual Basic, вероятно, перейдут на Visual Basic В С# для генерации предлагается великолепный синтаксис, который навер няка очарует очень многих. Зачем же тогда нужен C++?

По нескольким причинам. Во-первых, не исключено, что вы уже написа ли огромный объем реально кода на C++. И в каких-то слу чаях куда перекомпилировать ваши DLL в сборки Managed C++ (скажем, в некоем коде содержится крайне запутанная логика, которая обязательно должна в вашей системе). Другая причина в том, что вы, возможно, не готовы к переходу на С#. Синтаксис С# в целом четче синтаксиса C++;

в нем, например, не поддерживаются указатели. Однако к С# нужно еще привыкнуть. Наконец, последняя и, вероятно, самая вес кая причина использования Managed C++ заключается в том, что компи лятор Microsoft C++ хорошо оптимизирован. Это наиболее продвинутый и тонко настраиваемый компилятор для генерации выполняемого Сегодня я рассказал, что нужно для написания отделенного кода ASP страниц с использованием Managed C++. В дальнейшем я намерен рас смотреть применение Managed C++ при программировании других частей страниц ASP.NET.

Исходный код для этой статьи можно скачать по ссылке ASPColumn0208.exe.

Джордж (George Shepherd) создает средства разработки для в SyncFusion. Преподает на курсах в DevelopMentor и является автором целого ряда книг по программированию, в том числе Applied (Addison-Wesley, 2001). С ним можно по адресу Дино Эспозито На переднем крае Программирование форм в ASP.NET осваивать ASP.NET, часто на том, что управляемые Web-приложения нужно создавать в с моделью интерфейса на одной формы. Автор рассматривает вопросы программирования форм в ASP NET и показывает, как реализовать модель программирования на основе нескольких форм. В статье также описывается применение этой модели для мобильных элементов управления ASP.NET.

ASP-разработчики, начинающие осваивать ASP.NET, часто спотыкаются на что управляемые Web-приложения нужно создавать в соответ ствии с моделью интерфейса на основе одной формы (single-form interface, SFI). Не паникуйте Ч вы никогда не слышали о SFI. Я сам изобрел этот термин, чтобы провести аналогию с похожими моделями программирова ния, которые обозначаются такими аббревиатурами, как (single-docu ment interface) и (multiple-document interface). Надеюсь, это чуточ ку облегчит понимание концепции, изложенной в статье.

Б модели SFI каждая страница всегда отправляет данные самой себе, ис пользуя по умолчанию POST. HTTP-метод и фрейм, в кото рый посылаются данные, можно изменять программно через свойства фор мы Method и Target. Адрес, на который передаются данные, изменить нельзя Ч они всегда возвращаются форме. В HTML и ASP элемент поддерживает свойство Action, перенаправлять запрос на другой URL. В ASP.NET рендеринг серверных форм выполняется с помо щью класса HtmlForm. Последний не содержит ни привычного свойства Action, ни какого-либо другого аналогичного свойства. А значит, модель Публиковалось в 2003. № 5 (май). Ч Прим.

Программирование форм в ASP.NET SFI настолько глубоко вкопана в ASP.NET, что обойти ее нет никакой воз можности.

В этой статье я рассмотрю программирование форм в ASP.NET и покажу, как реализовать модель программирования на основе нескольких форм.

Попутно я опишу детали такой модели, доступной для мобильных элемен тов управления ASP.NET.

Почему появилась модель программирования на основе одной формы С технической точки зрения, реализация интерфейса на основе несколь ких форм (multi-form interface, Ч опять мое изобретение! Ч в ASP.NET возможна, но для этого придется попотеть. такова, что в ней размещается ровно одна серверная форма. как я потом покажу, вы можете добавить сколько угодно HTML-тэгов без атрибута ranat.

Если вы размещаете на странице более одной серверной формы, то не по лучаете никаких ошибок при компиляции. запрос к стра нице обрабатывается, как обычно, Ч кодом базового класса Page. Сначала для страницы генерируется временный класс, затем он компилируется и, наконец, загружается. Исполняющая среда ASP.NET начинает обработку запроса к странице и, как всегда, вызывает события Load и PreRender.

Все эти события обрабатываются совершенно нормально. После их обра ботки начинается рендеринг страницы.

Соответствующий странице класс вызывает метод Render для всех эле ментов управления на этой странице. Таким образом, первый блок успешно обрабатывается и отображается. После этого объект страницы устанавливает внутренний флаг, что для этой страницы один объект формы уже обработан. Угадайте, что будет дальше?

При обнаружении блока

Ч защищенный виртуальный метод, определенный в клас се HtmlForm. Он выполняет рендеринг дочерних элементов управления ASP.NET формы, дважды вызывая внутренние методы объекта Page. Вот как это выглядит в псевдокоде:

virtual void writer) { и ~ внутренние методы класса Page, управляющие рендерингом форм. В частности, первый метод устанавли вает булеву переменную, отвечающую за генерацию исключения (рис. 1).

Следующий псевдокод структуру метода OnFormRender:

void writer, string { if throw new serverFormCreated = 3 have only one form lad Server Error in A page can one Form tag.

Description: An occurred of the current Please review the stack for more information where it A one -side Source Error:

An during of location of exception be identified using the exception trace Stack Trace:

[HttpException A page can have writer, String + System. Html writer) writer) + writer) + Рис. 1. Ошибка Программирование форм в ASP.NET Что это означает для нас? В ASP.NET число серверных форм при ком пиляции не контролируется. На странице Web Forms вы могли бы разме стить сколько угодно серверных форм, но при условии, что в каждый мо мент времени видима лишь одна из них. На практике, если установить для остальных серверных форм атрибут Visible в false, рендеринг страницы пройдет нормально. Конечно, можно программно управлять этим атрибу том и выбирать, какую из форм выводить, в зависимости от неких условий в период выполнения. Кстати, этот подход аналогичен тому, который под держивается мобильными формами ASP.NET, где допускается определе ние нескольких серверных форм, но в каждый момент видимой является только одна из них. На рис. 2 показана тривиальная страница ASP.NET, содержащая несколько взаимно исключающих друг друга форм.

Рис. 2. Несколько форм Модель на основе одной формы имеет ключевое значение для реализации поддержки состояний в ASP.NET. Так как страница всегда отправляет дан ные сама себе, исполняющей среде легко считывать и восстанавливать со стояние, сохраненное в момент последнего обращения. Хотя для сохране ния и восстановления состояния страницы существуют и другие способы, применение модели на основе одной формы Ч самое простое и эффектив ное решение.

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

Той же функциональностью обладают и другие классы элементов управ ления HTML, например Интерфейс lAttributeAccessor опреде ляет два метода: GetAttribute и SetAttribute. Они используются при чте нии значений атрибутов из открывающего тэга.

Класс обеспечивает программный доступ к HTML-элементу на серверной стороне через набор свойств, перечисленных в табл.

У формы должно быть уникальное имя. Если оно не задано программис том, его генерирует ASP.NET по шаблону где X Ч уникальное целое число (обычно порядковый номер элемента управления на странице).

Программист может указать идентификатор формы через свойство ID или свойство Name. Если установлены оба свойства, преимущество отдается ID. На его основе ASP.NET формирует значения и Ч это полностью определенная (fully qualified) строка, основан ная на именующем контейнере формы (naming container of the form) (в его роли обычно выступает сама страница). В свою очередь ClientlD исполь зуется для идентификации элемента управления в операциях, выполняе мых на клиентской стороне, например в функциях JavaScript, Впрочем, эта логика применяется не только к формам, но и ко всем серверным элемен там управления.

Табл. 1. Свойства Свойство Описание Attributes Возвращает набор (collection) вида лимя-значение, содержа щий все атрибуты тэга ClientlD Возвращает значение UniquelD Controls Получает объект набора, представляющий все дочерние элементы формы Disabled Получает или устанавливает значение, указывающее, отклю чена ли форма;

соответствует HTML-атрибуту disabled На этом уровне используется редко;

получает или устанавли вает значение, указывающее, следует ли сохранять состояние дочерних элементов управления см. след. стр.

Программирование форм ASP.NE Табл. 1. Свойства Свойство Описание Получает или устанавливает тип кодирования;

соответствует HTML-атрибуту enctype ID Получает или устанавливает программный идентификатор формы Получает или устанавливает текст разметки, находящийся между открывающим и закрывающим тэгами формы Получает или устанавливает текст, находящийся между открывающим и закрывающим тэгами формы Method Указывает, как браузер возвращает форму на сервер (по умолчанию Ч POST);

при необходимости можно указать GET Name Возвращает значение UniquelD Получает ссылку на именующий контейнер формы (обычно это хост-страница) Получает ссылку на хост-страницу Page Parent Получает ссылку на родительский объект (обычно, хотя и не обязательно, это страница) Site Возвращает Style Получает набор всех свойств таблицы каскадных стилей, применяемой к форме Возвращает Target Получаст или устанавливает имя фрейма или окна, в котором нужно отобразить сгенерированный для страницы HTML plate Source- Получает виртуальный каталог страницы, содержащей форму Directory Получает уникальное, полностью определенное имя формы Visible Если равно false, форма не транслируется в HTML Родительский объект формы Ч это самый внутренний (innermost) контей нер с атрибутом Если такой элемент управления отсутствует, роди тельским является объект страницы. К типичным контейнерам серверных форм относятся элементы

is

и если они помечены атрибутом По умолчанию свойство Method равно POST. Его значение можно менять программно. Если форма отправляется методом GET, все ее данные пере даются в строке запроса URL. Выбрав этот метод, не забудьте, что ограни чение на размер GET-запроса может привести к отсечению части данных.

Будьте осторожны.

В табл. 2 перечислены методы, доступные в классе Все они унаследованы от базового класса Обратите внима ASP.NET что метод осуществляет поиск только внутри именующе го контейнера формы. Элементы управления, принадлежащие внутренне му именующему контейнеру (например пользовательский элемент управ ления или не обнаруживаются.

Табл. 2. Методы HTMLForm Метод Описание Вызывает метод для всех элементов управления на форме Dispose Выполняет очистку перед освобождением формы FindControl Ищет и возвращает все дочерние элементы управления с указанным ID HasControls Указывает, содержит ли форма какие-либо дочерние элементы управления Выводит HTML-ход для формы;

если включена трассировка, кэширует трассировочную информацию для последующего ее вывода в конце страницы ResolveUrl Гарантирует абсолютность указанного URL;

считывает базы из свойства Класс HtmlForm не запечатан поэтому от можно наследовать другие классы. Он также содержит ряд защищенных перегружаемых мето которые позволяют полностью изменять его поведение.

Работа с формами в Для некоторых страниц требуется несколько логических форм. Логичес кая форма Ч не обязательно HTML-форма в классическом ее понимании.

Это просто группа логически элементов управления для ввода, содержимое которых одновременно передается коду, способному обрабо тать их данные. Такая группа управления ведет себя подобно форме. Применение тэга для объединения этих элементов Ч са мый простой способ создания логической формы. Увы, ASP.NET не позво ляет использовать более одного серверного тэга . Но логические формы можно реализовать и другими способами.

Для примера возьмем страницу авторизации (login page), предназначен ную для доступа к закрытым областям Web-сайта. Зарегистрированные пользователи просто вводят свои учетные данные и соединяются. Незаре гистрированные пользователи должны заполнить форму перед тем, как получат параметры, необходимые для соединения. Как реализовать эту логику? Рассмотрим несколько вариантов.

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

и и на Рис. 3. Отправка Закрытая Рис. 4. Более подходящее для ASP.NET решение Единственный тэг содержит несколько логических Все ло гические формы отправляют данные одной и той же странице и скрывают ненужные элементы пользовательского интерфейса Внутри откры вающего и закрывающего тэгов единственной формы может находится две или более групп логически связанных элементов управления. Каждая группа может данные на сервер либо с помощью традицион Microsoft ASP.NET ной кнопки Submit, либо с помощью связанной с кодом сце нария (script), в ASP.NET это называется кнопкой-ссылкой (link but ton). Хотя в техническом смысле такие группы не являются формами, они ведут себя так же, как HTML-формы. Все группы отправляют данные од ной и той же странице, но инфраструктура ASP.NET гарантирует сохране ние состояния и выполнение кода, указанного для группы, которая иници ировала отправку. Каждая кнопка-ссылка связана с серверным выполняемым при возврате страницы на сервер после щелчка этой кнопки.

С функциональной точки этот механизм ничем не отличается от Но с точки программирования, он удобнее за счет более высокого уровня абстракции и поддержки таких полезных возмож ностей, как использование состояния отображения (view state) и програм мирование серверных элементов управления.

Как обновлять в генерируемом HTML? В ASP.NET серверные элемен ты управления можно программно скрывать и отображать. Элементы уп равления, свойство Visible которых равно false, игнорируются синтакси ческим анализатором (parser) ASP.NET, и для них не формируется HTML код. В соответствии с рис, 4 вы можете спроектировать страницу автори зации, содержащую три блока HTML-кода. Первый блок Ч авторизацион ная форма, второй Ч регистрационная, третий Ч закрытые данные. При первом отображении страницы (когда IsPostBack равно false) работают блоки авторизации и регистрации, а закрытая область остается невидимой.

Затем пользователь выбирает либо авторизацию, либо регистрацию. Стра ница возвращает введенные данные на сервер и выполняет код. После ре гистрации нового пользователя или проверки учетных данных существу ющего вы просто выключаете первых двух форм и делаете ви димой третью.

Код на рис. 5 реализует форму с двумя логическими одна из них содержит кнопку, вторая - обычные поля авторизации. Обе формы помещены внутрь серверного контейнера При первом отображении страницы видна только первая псевдоформа. При щелчке кнопки скрыва ется блок и отображается блок Login. He забудьте: когда атрибут Visible равен false, код для элементов управления не генерируется.

Рис. 5. Две логические script sender, см. след. стр.

форм a Рис. 5. Две логические sender, e) ftesOlg. = * false;

Click to login, /> id Таким образом, вы создаете страницу, которая содержит несколько логи ческих форм, но одновременно показывает только одну из них. Само со бой, этот способ можно усовершенствовать и выполнять код на внешней странице. До сих пор я полагал, что код, обрабатывающий содержимое логической формы находится на хост-странице. Однако ничто не мешает передать управление другой странице, тем самым имитируя HTML-фор му. Для более эффективной реализации решения, приведенного на рис. 5, примените пользовательские элементы управления и поместите внутрь них содержимое серверных блоков В принципе, если у вас складывается впечатление, что иного пути, кроме использования нескольких форм нет, то, возможно, вам стоит перерабо тать код. Увеличив уровень абстракции, вы сможете создать такую же по функциональности ASP.NET-страницу с единственной формой. В ASP.NET следует оперировать классами и функциональностью, а не HTML-формами. Но иногда, особенно если вы занимаетесь переносом на новую платформу сложного Web-сайта (например портала), лучшим спо собом, позволяющим сэкономить время и деньги, может оказаться приме нение нескольких форм.

Чтобы более эффективно задействовать преимущества ASP.NET, зачастую имеет смысл перепроектировать свое приложение и отказаться от исполь зования нескольких HTML-форм. Если формы ссылаются на совершенно разные страницы (поисковые или подумайте о расширении и имитации поддержки нескольких форм без потери средств поддержки состояния, присущих ASP.NET.

Использование нескольких тэгов Если автоматическая поддержка состояний не нужна, создать несколько HTML-форм на одной несложно. Но помните, что только для одной из них атрибут может быть равным Сле довательно, лишь для элементов управления, содержащихся на этой фор ме, ASP.NET обеспечивает управление состоянием и поддерживает собы тия возврата формы на сервер events). Рассмотрим код страни цы Web Forms, приведенный на рис. 6.

Рис. 6, Страница Web Forms -> Х back" /> /> Как видите, атрибуты runat второго и третьего тэгов не равны поэтому исполняющая среда ASP.NET воспринимает эти тэги как простой текст и при отправке никак не обрабатывает. При щелчке кнопки Программирование форм в ASP.NET submitl браузер переходит на страницу Это совершенно но вая которой ничего не известно об элементах управле ния на главной странице. Данные с страницы можно полу чить, только пользуясь старым стилем программирования ASP, и только с формы, вызвавшей отправку данных.

Page void sender, EventArgs e) { I ASP.NET игнорирует элементы управления, определенные вне первой сер верной формы страницы. При щелчке кнопки передачи (submit), связан ной с серверной формой, страница отправляет данные сама себе, но при этом содержимое всех остальных полей очищается. Тот же побочный эф фект возникает при передаче данных с помощью третьей кнопки Ч кноп ки Submit на HTML-форме, отправляющей данные той же странице Передача данных текущей странице Ч как раз то, что и должно быть в ASP.NET, но почему этого не происходит при отправке данных из клиент ской HTML-формы?

Все просто Ч работающий на серверной стороне класс не толь ко генерирует необходимый для формы HTML, но и выполняет код, уста навливающий состояния элементов управления формы. Это преимуще ство игры по правилам ASP.NET.

Можно ли применять несколько серверных форм в приложении ASP.NET?

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

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

Microsoft /> /> Помимо управления дочерними элементами, пользовательские элементы управления предоставляют базовый набор функций, в частности свойство Action. В следующем фрагменте кода приведен пример пользовательско го элемента управления Control X>
/> He нужно добавлять свойство Action и метод Submit к каждому пользова тельскому элементу. Достаточно наследовать пользовательские элементы от некоего базового класса. В моем коде базовым классом является Form (рис. 7).

Рис. 7. Базовый класс namespace { public о С - это которые // могут в следующих + parts = // часть управления // ключом наборе Context, Для обращения // к // используйте имя.

Page, см. след. стр.

Программирование форм ASP.NET Рис. 7. Базовый класс Базовый класс содержит открытое свойство Action и метод Submit, приме няемый в качестве обработчика события. Когда пользователь щелкает кнопку Submit в аналогичном пользовательском элементе управления, код извлекает все значения формы, относящиеся к пользовательскому элемен ту. Этот элемент является именующим контейнером, поэтому к именам всех дочерних элементов управления добавляется его идентификатор.

Цикл foreach на рис. 7 перебирает все страничные объекты Request и из влекает значения, относящиеся к пользовательскому элементу управле ния. (Обратите внимание на знак двоеточия: на самом деле это деталь реа лизации, которая может измениться в будущем.) Значения сохраняются в объекте представляющем контекст обрабатываемого запроса.

Это глобальный объект, чей срок жизни со временем существо вания запроса. После заполнения набора Context.Items метод Submit пе редает управление странице, указанной в свойстве Action.

Как эта страница получает значения из вызывавшей ее формы? Конечно же, входные данные считываются из контекста запроса: