Партнерка на США и Канаду по недвижимости, выплаты в крипто

  • 30% recurring commission
  • Выплаты в USDT
  • Вывод каждую неделю
  • Комиссия до 5 лет за каждого referral

Разработка «коммерческих» приложений в среде. NET

Тема №3. Разработка WebBased-приложений


3. Разработка Web-приложений на

Платформа — это набор программных технологий, призванных упростить разработку современных Web - и Windows-приложений. В этом разделе рассматривается часть платформы. NET под названием , используемая для написания программ, которые обычно называют WebBased-приложениями. Она позволяет создавать динамические страницы HTML. возникла в результате объединения более старой технологии ASP (активные серверные страницы) и. NET Framework. Она содержит множество готовых элементов управления, применяя которые можно быстро создавать интерактивные web-сайты. Мы также можем использовать сервисы, предоставляемые другими сайтами, прозрачно для пользователей вашего сайта

Веб-приложения — сущность совершенно иного рода, чем настольные приложения (как минимум). Первое очевидное отличие состоит в том, что профессиональное веб-приложение всегда подразумевает существование как минимум двух машин, объединенных в сеть (конечно, во время разработки вполне возможно для одной машины исполнять роль и веб-сервера, и браузерного клиента). Учитывая природу веб-приложений, объединенные в сеть машины должны договориться об используемом сетевом протоколе для определения способа отправки и получения данных. Сетевой протокол, соединяющий эти компьютеры, называется HTTP (Hypertext Transfer Protocol).

Когда клиентская машина запускает веб-браузер (такой как Opera, Mozilla Firefox или Microsoft Internet Explorer), выполняется HTTP-запрос для доступа к определенному ресурсу (обычно веб-странице) на удаленной серверной машине. HTTP представляет собой основанный на тексте протокол, построенный на основе стандартной парадигмы запрос/ответ. Например, если вы переходите к http://www. , то программное обеспечение браузера полагается на технологию DNS (Domain Name Service), которая преобразует запрошенный URL в 32-битное числовое значение, состоящее из четырех частей и именуемое IPv4-адресом. И в этот момент браузер открывает так называемый сокет для соединения (обычно через порт 80 для открытых подключений) и посылает HTTP-запрос для обработки на целевом сайте.

НЕ нашли? Не то? Что вы ищете?

Веб-сервер принимает входящий запрос HTTP и может обработать любые отправленные клиентом входные значения (такие как значения, введенные в текстовых полях, чекбоксы, переключатели и т. п.), формирующие правильный HTTP-ответ.

Веб-программисты могут использовать множество технологий (CGI, ASP, , JSP и т. п.) для динамической генерации содержимого, помещаемого в НTTР-ответ. После этого браузер на клиентской стороне визуализирует HTML, отправленный веб-сервером.

Другой аспект веб-разработки, который заметно отличает ее от традиционного настольного программирования, состоит в том, что HTTP — это, по сути, сетевой протокол без поддержки состояния. Как только веб-сервер отправил ответ клиенту, все их предыдущее взаимодействие забывается. Это определенно не так, как в традиционном настольном приложении, где состояние исполняемой программы остается актуальным и изменяется в процессе взаимодействия до тех пор, пока пользователь не закроет приложение.

Учитывая это на веб-разработчика, возлагается ответственность за «сохранение» информации (наподобие выбранных товаров в корзине покупок, номеров кредиток, различных адресов и т. д.) о пользователях, которые на данный момент прошли регистрацию на нашем сайте. Технология предлагает многочисленные способы обработки состояния, многие из которых уже стали общим местом для любой веб-платформы (сеансовые переменные, cookie-наборы и переменные приложения), а также некоторые специфичные для. NET технологии, вроде API-интерфейса управления профилями .

Веб-приложение можно понимать как набор файлов (*.htm, *.asp, *.aspx, изображений, данных XML и т. п.), а также связанных с ними компонентов (таких как библиотека кода. NET или унаследованный COM-сервер), хранящуюся в определенном множестве каталогов на данном веб-сервере. Веб-приложения имеют специфический жизненный цикл и предоставляют многочисленные события (вроде начального запуска или финального останова), которые можно перехватывать для выполнения специализированной обработки во время операций с веб-сайтом.

Веб-сервер — это программная система, отвечающая за размещение веб-приложений, обычно предоставляющий множество взаимосвязанных служб, таких как интегрированная безопасность, поддержка протокола передачи файлов FTP), службы почтового обмена и т. д.

Службы Internet Information Services (IIS) — это веб-серверный продукт, который обладает встроенной поддержкой приложений классического ASP и .

Когда мы строим веб-приложения , то обычно требуется взаимодействие с IIS. Однако IIS не выбирается по умолчанию в качестве опции инсталляции операционной системы Windows (кстати, не все версии Windows могут поддерживать IIS, например, Windows XP Home не может). Поэтому, в зависимости от конфигурации машины разработки, может понадобиться инсталлировать IIS перед тем, как разрабатывать -приложения. Для этого надо запустить аплет Add/Remove Program (Установка и удаление программ) панели управления и выбрать Add/Remove Windows Components (Установка компонентов Windows). Администрирование IIS также доступно через панель управления Windows. Дальнейшее очевидно, а если нет, то рекомендуется внимательно просмотреть справочную систему.

Единственная инсталляция IIS может поддерживать многочисленные веб-приложения, каждое из которых располагается в своем виртуальном каталоге. Каждый виртуальный каталог отображается на физический каталог на жестком диске. Поэтому, если мы создаем новый виртуальный каталог по имени KYKYREKY, то внешнему миру он доступен по адресу типа http://www. , с учетом того, что у нас есть IPv4-адрес нашего сайта. «За кулисами» этот виртуальный каталог отображается на физический корневой каталог на веб-сервере, например, C:\inetpub\wwwroot\AspNetKykyrekySite, который хранит содержимое веб-приложения KYKYREKY.

Когда настроен каталог для размещения веб-приложения и выбран веб-сервер для использования в качестве хоста, нужно создать само содержимое. Напомним, что под «веб-приложением» мы понимаем набор файлов, составляющих функциональность сайта. Большинство из этих файлов будут содержать лексемы, определенные языком HTML. Известно, что HTML— это стандартный язык разметки, используемый для описания того, как литеральный текст, графические образы, внешние ссылки и различные виджеты пользовательского интерфейса на базе HTML отображаются внутри браузера клиентской стороны.

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

• Проверка пользовательского ввода перед отправкой данных обратно веб-серверу.

• Взаимодействие с объектной моделью документов (Document Object Model — DOM) целевого браузера.

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

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

предоставляет свойство HttpRequest.Browser, позволяющее определять во время выполнения возможности браузера, который прислал текущий запрос.

Возникает вопрос: а как передать данные формы обратно веб-серверу для обработки. Когда мы строите форму HTML, то обычно указываете атрибут action в открывающем дескрипторе <form>, чтобы специфицировать получателя входных данных формы. Возможные получатели включают почтовые сервера, другие файлы HTML, файлы Active Server Pages (ASP) и т. п. Например,

<form name="defaultPage" id="defaultPage"

action="http://localhost/Kykyreky/AspPage. asp" method="GET">

</form>

Эти дополнительные атрибуты гарантируют, что когда произойдет щелчок на кнопке Submit, данные формы будут отправлены странице AspPage. asp по указанному URL. Когда в качестве режима передачи указано method="GET", данные формы добавляются к строке запроса в виде набора пар имя/значение, разделенных амперсандами:

http://localhost/Kykyreky/AspPage. asp? txtUserName=

Alejandro&txtPassword=Foo$&btnSubmit=Submit

Другой метод передачи данных формы на веб-сервер задается как method="POST":

<form name="defaultPage" id="defaultPage"

action="http://localhost/Kykyreky/AspPage. asp. asp" method = "POST">

</form>

В этом случае данные формы не добавляются к строке запроса, а вместо этого записываются в отдельную строку внутри заголовка HTTP. При использовании метода POST данные формы не становятся непосредственно видимыми внешнему миру. Что более важно, данные POST не имеют ограничения по длине строки (многие браузеры ограничивают длину запросов GET).

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

• Новые элементы управления для поддержки разработки Silverlight (это API-интерфейс на базе WPF для проектирования богатого медиа-содержимого веб-сайта).

• Интегрированная поддержка разработки в стиле Аjах, которая по сути позволяет выполнять «обратные микро-отправки» для обновления части веб-страницы насколько возможно быстро.

Поскольку наш курс не посвящена специально веб-разработке, за дополнительными деталями по упомянутым здесь вопросам обращайтесь к документации по. NET Framework 4.0.

3.1 Пространства имен


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

• Основная функциональность (т. е. типы, позволяющие взаимодействовать с запросами и ответами HTTP, инфраструктурой Web Forms, поддержкой тем и профилирования, веб-частями, безопасностью и т. п.).

• Элементы управления Web Forms и HTML.

• Мобильная веб-разработка.

• Разработка Silverlight.

• Разработка Ajax.

• Веб-службы XML.

Веб-страницы могут быть сконструированы на базе одного из двух подходов. Можно создать единственный файл *.aspx, который будет содержать смесь кода серверной стороны и HTML (подобно классическому ASP). При использовании однофайловой модели страницы код серверной стороны помещается в область <script>, но сам код не является кодом сценария (т. е. VBScript/JavaScript). Вместо этого операторы кода внутри блока <script> пишутся на любом языке программирования. NET на наш выбор (С#, Visual Basic и т. п.).

При построении страницы, содержащей очень немного кода (но много HTML), однофайловая модель страницы может быть проще в работе, поскольку мы видим код и разметку в одном объединенном файле *.aspx. Вдобавок, размещение кода и разметки HTML в одном файле обеспечивает ряд других преимуществ.

• Страницы, написанные с использованием однофайловой модели, несколько легче развертывать или передавать другому разработчику.

• Поскольку между файлами нет зависимостей, такую страницу в одном файле легче переименовать.

• Управление файлами в системах управления версиями несколько облегчается, так как все действия предпринимаются в единственном файле. Подход по умолчанию при создании нового решения веб-сайта состоит в использовании техники, известной как отделенный код, которая позволяет отделить программный код от логики презентации HTML, используя два разных файла. Этот метод работает достаточно хорошо, когда страница содержит значительный объем кода, или когда несколько разработчиков трудятся над одним и тем же веб-сайтом. Модель отделенного кода также представляет ряд преимуществ.

• Поскольку страницы с отделенным кодом обеспечивают четкое разделение разметки HTML и кода, можно организовать одновременную работу дизайнеров над разметкой и программистов— над кодом С#.

• Код не показан дизайнерам страниц, которые имеют дело только с разметкой (как и можно было предположить, специалистам по HTML не всегда интересно видеть устройство кода С#).

• Одни и те же файлы кода могут использоваться со многими файлами *.aspx.

Независимо от выбранного подхода, в смысле производительности никакой разницы нет. Фактически многие веб-приложения выигрывают от применения обоих подходов.

Типичный файл *. aspx обычно открывается набором директив. Директивы всегда помечаются маркерами <%@ ... %> и могут быть квалифицированы различными атрибутами, информирующими исполняющую систему о том, как следует обрабатывать каждый атрибут.


Каждый файл *.aspx должен иметь, как минимум, директиву <%@Раgе%>, которая служит для определения управляемого языка, применяемого внутри страницы (в атрибуте language). Также директива <%@Раgе%> может определять имя связанного файла отделенного кода (если он есть), включать поддержку трассировки и т. д.

В дополнение к директиве <%@Раgе%>, заданный файл *.aspx может специфицировать различные директивы <%@import%> для явной установки пространств имен, необходимых текущей странице, и директив <%@Assembly%> для указания внешних библиотек кода, используемых сайтом и обычно размещаемых в папке \bin).

При однофайловой модели страницы файл *.aspx может содержать логику сценариев серверной стороны, которая выполняется на веб-сервере. Учитывая это, очень важно, чтобы все блоки кода серверной стороны были определены для выполнения на сервере с помощью атрибута runat="server". Если атрибут runat="server" не указан, то исполняющая система предполагает, что пишется блок сценария клиентской стороны, встраиваемый в ответ HTTP:

<script runat="server">

void btnFillData_Click(object sender, EventArgs args)

{

...

}

</script>

Сигнатура этого вспомогательного метода должна показаться странно знакомой. И действительно, из нашего знакомства с Windows Forms, обработчик событий контрола должен соответствовать шаблону, определенному связанным делегатом. NET. И, как в Windows Forms, когда мы хотим обработать щелчок на кнопке на серверной стороне, делегатом должен быть System. EventHandler, который может вызывать только методы, принимающие System. Object в первом параметре и System. EventArgs — во втором.

Примерами часто используемых Web Forms-контролов являются Button, Label и GridView. Подобно классическому ASP и «плоскому» HTML, веб-виджеты помещаются в область элементов <form>. На этот раз, однако, открывающий дескриптор <form> помечен атрибутом runat="server". Это важно, поскольку этот дескриптор информирует исполняющую систему о том, что перед передачей HTML в поток ответа виджеты имеют шанс визуализировать свое HTML-представление:

<form id="forml" runat="server">

<div>

<asp:Label ID="lblInfo" runat=Mserver"

Text="Click on the Button to Fill the Grid">

</asp:Label>

<br />

<br />

<asp:GridView ID="carsGridView" runat="server">

</asp:GridView>

<br />

<asp:Button ID="btnFillData" runat="server" Text="Fill Grid" />

</div>

</form>

Обратите внимание, что веб-контролы объявлены с дескрипторами <asp> и </asp> и также помечены атрибутом runat="server". Внутри открывающего дескриптора специфицируется имя элемента управления Web Forms и любое количество пар имя/значение, которые будут применяться во время выполнения для визуализации корректного HTML.

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

Если мы используем однофайловую модель страницы, то разметка HTML, блоки <script> серверной стороны и определения веб-контролов динамически компилируются в тип класса, унаследованный от System. Web. UI. Page. Имя этого класса базируется на имени файла *.aspx с добавлением суффикса _aspx (т. е. страница по имени MyPage. aspx становится типом класса по имени MyPage_aspx) и т. д. На рис. показан базовый процесс.


3.2 Веб-элементы управления, темы и мастер-страницы

Главным преимуществом является возможность собирать пользовательский интерфейс страниц, используя типы, определенные в пространстве имен System. Web. Ul. WebControls. Эти элементы управления (которые называются серверными элементами управления, веб-элементами управления или элементами управления Web Form) исключительно полезны в том, что автоматически генерируют необходимый HTML для запрашивающего браузера и представляют набор событий, которые могут быть обработаны на веб-сервере. Более того, поскольку каждый контрол имеет соответствующий класс в пространстве имен System. Web. Ul. WebControls, им можно манипулировать в объектно-ориентированной манере.

При конфигурировании свойств веб-элемента управления в окне Properties (Свойства) среды Visual Studio 2010, изменения фиксируются в открывающем дескрипторе объявления данного элемента в файле *.aspx как последовательность пар имя/значение.

Таким образом, если добавить новый элемент TextBox в дизайнере и изменить его свойства ID, BorderStyle, BorderWidth, BackColor и Text, открывающий дескриптор <asp:TextBox> будет модифицирован соответственно (значение Text становится внутренним текстом в области TextBox):

<asp:TextBox ID="txtNameTextBox" runat="server" BackColor="#C0FFC0" BorderStyle="Dotted"

BorderWidth="1px">

Enter Your Name

</asp:TextBox>

Учитывая, что HTML-объявление веб-контрола в конечном итоге становится переменной-членом из пространства имен System. Web. Ul. WebControls (через цикл динамической компиляции), можно взаимодействовать с членами этого типа внутри блока <script> серверной стороны или внутри файла отделенного кода. Например, если мы обрабатываем событие Click для определенного типа Button, то можете изменить цвет фона элемента TextBox следующим образом:

partial class _Default : System. Web. UI. Page

{

protected void btnChangeTextBoxColor_Click(object sender, System. EventArgs e)

{

// Изменить цвет объекта - текстового поля в коде.

this. txtNameTextBox. BackColor = System. Drawing. Color. DarkBlue;

}

}

Все веб-элементы управления в конечном итоге наследуются от общего базового класса System. Web. Ul. WebControls. WebControl, который, в свою очередь, унаследован от System. Web. UI. Control (а тот — от System. Object). И Control, и WebControl определяют ряд свойств, общих для всех элементов управления серверной стороны.

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

Хотя серверные контролы выполняют большую работу, изолируя от деталей "сырого" протокола HTTP, всегда стоит помнить, что восприятие WWW как управляемой событиями сущности — всего лишь маскировка, которую обеспечивает CLR, и не имеет ничего общего с управляемой событиями модели пользовательских интерфейсов на базе Windows.

Так, например, хотя пространства имен System. Windows. Forms, System. Windows. Controls и System. Web. Ul. WebControls определяют типы с теми же простыми именами (Button, TextBox, Label и т. д.), они не предоставляют идентичных наборов событий. Например, нет способа обработать событие серверной стороны MouseMove, когда пользователь перемещает курсор над элементом Web Forms по имени Button. Но вряд ли кому-то нужно выполнять обратную отправку на сервер при каждом движении мыши в браузере.

Отрицательным фактором является то, что данный веб-контрол представляет ограниченный набор событий, и все они в конечном итоге подразумевают обратную отправку на веб-сервер. Любая необходимая обработка событий клиентской стороны потребует написания массы кода сценариев JavaScript/VBScript клиентской стороны для обработки механизмом выполнения сценариев запросившего браузера.

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

Тип System. Web. UI. Control

Базовый класс System. Web. UI. Control определяет различные свойства и события, которые обеспечивают возможность взаимодействия с основными (обычно не GUI) аспектами веб-элемента управления.

Первый аспект System. Web. UI. Control, который мы рассмотрим — это тот факт, что все веб-элементы управления (включая Page) наследуют коллекцию специальных элементов, доступную через свойство Controls). Во многом подобно приложениям Windows Forms, свойство Controls предоставляет доступ к строго типизованной коллекции типов-наследников WebControl. Подобно любой коллекции. NET, здесь имеется возможность динамически добавлять, вставлять и удалять элементы во время выполнения.

Хотя технически возможно добавлять новые элементы управления непосредственно к типу-наследнику Page, надежнее использовать виджет Panel. Класс Panel представляет контейнер виджетов, которые могут или не могут быть видимы конечному пользователю (в зависимости от значений свойств Visible и BorderStyle).

СЛУШАТЕЛЯМ: СОЗДАТЬ Web-приложения для перечисления контролов в панели (добавьте элемент типа Panel (по имени myPanel), содержащий в себе TextBox, Button, HyperLink. Также добавьте на форму контрол Label. При загрузке страницы на нем отображается список контролов).

Получим что-то вроде следующего кода:

private void ListControlsInPanel()

{

string thelnfo = "";

thelnfo = string. Format("Has controls? {0} <br/>", myPanel. HasControls());

foreach (Control c in myPanel. Controls)

{

if (!object. ReferenceEquals(c. GetType()

, typeof(System. Web. UI. LiteralControl)))

{

thelnfo += "***<br/>";

thelnfo += string. Format("Control Name? {0} <br/>", c. ToString());

thelnfo += string. Format("ID? {0} <br>", c. ID);

thelnfo += string. Format("Control Visible? {0} <br/>", c. Visible);

thelnfo += string. Format("ViewState? {0} <br/>", c. EnableViewState);

lblControlList. Text = thelnfo;

}

}

}

А что если нужно модифицировать содержимое Panel во время выполнения?

Давайте обновим полученную страницу для поддержки дополнительного элемента Button (по имени bntAddWidgets), который будет динамически добавлять к Panel три новых элемента типа TextBox, и еще один элемент Button (по имени btnRemovePanelItems), который очистит Panel от всех вложенных элементов управления. Обработчики события Click для каждой кнопки показаны ниже:

protected void btnRemovePanelItems_Click(object sender, EventArgs e)

{

myPanel. Controls. Clear();

ListControlsInPanel();

}

protected void btnAddPanelItems_Click(object sender, EventArgs e)

{

for (int i = 0; i < 3; i++)

{

// Присвоить имя, чтобы можно было позднее получить текстовое значение

//с использованием входных данных формы.

TextBox t = new TextBox();

t. ID = string. Format("newTextBox{0}", i);

myPanel. Controls. Add(t);

ListControlsInPanel();

}

}

Каждому TextBox присваивается уникальный идентификатор (newTextBox1, newTextBox2 и т. д.) для программного получения содержащегося в нем текста с использованием коллекции HttpRequest.Form.

Для получения значений из этих динамически генерированных элементов TextBox нужно обновить пользовательский интерфейс, добавив дополнительные элементы типа Button и Label. Внутри обработчика события Click для Button выполните цикл по всем элементам, содержащимся в коллекции типа HttpRequest. NameValueCollection (доступной через HttpRequest. Form), и присоедините текстовую информацию к локальной переменной типа System. String. Пройдя всю коллекцию, присвойте значение этой строки свойству Text нового виджета Label по имени lblTextBoxText:

protected void btnGetTextBoxValues_Click(object sender, EventArgs e)

{

string textBoxValues = "";

for (int i = 0; i < Request. Form. Count; i++)

{

textBoxValues += string. Format("<li>{0}</li><br/>", Request. Form[i]);

}

lblTextBoxText. Text = textBoxValues;

}

После запуска приложения мы обнаружим, что содержимое каждого текстового поля можно просматривать в виде довольно длинной нечитабельной строки /wEWCALB4JaqDAK+tZO0BgLR49OXDQLT8MqYCAKaob+iDgL976PRCALem9bZCwKp5KjnBm6OzYUhl9nr6zi1/Qs+/E4pRz3KcILL16HzoorTP/1F

Эта строка содержит состояние представления (view state) каждого виджета на странице и будет рассмотрена далее. Также мы заметим, что как только запрос обработан, текстовое поле исчезнет. Причина этого кроется в не поддерживающей состояние природе HTML. Если мы хотим поддерживать эти динамически созданные TextBox между обратными отправками, следует сохранить эти объекты с использованием приемов программирования состояния .

Тип System. Web. UI .WebControls. WebControl


Как видно, тип Control имеет ряд характеристик поведения, не связанных с GUI (коллекцию вложенных элементов, поддержка обратной отправки и т. д.). С другой стороны, базовый класс WebControl предоставляет графический полиморфный интерфейс всем виджетам

Типы из пространства имен System. Web. UI. WebControls могут быть разделены на несколько основных категорий:

• простые элементы управления;

• элементы управления с развитыми средствами;

• элементы управления, ориентированные на данные;

• элементы управления проверкой достоверности ввода;

• элементы управления веб-частями;

• элементы управления безопасностью.

Простые элементы управления называются так потому, что они являются веб-элементами , которые отображаются на стандартные виджеты HTML (кнопки, списки, гиперссылки, изображения, таблицы и т. п.). Кроме того, есть небольшой набор элементов управления с развитыми средствами, для которых нет прямого эквивалента HTML (такие как Calendar, TreeView, Menu, Wizard и т. п.). Элементы управления, ориентированные на данные— это виджеты, которые обычно наполняются через подключение к некоторому источнику данных. Лучшим примером такого элемента может служить элемент GridView. Другие члены этой категории включают элементы-повторители (repeater) и легковесный DataList.

Элементы управления проверкой достоверности— это виджеты серверной стороны, которые автоматически генерируют код JavaScript клиентской стороны, необходимый для проверки значений, вводимых в элементы форм. Эти элементы пользовательского интерфейса инкапсулируют детали регистрации на сайте, предоставляют службы, связанные с паролями и управлением ролями пользователей. Полный набор веб-элементов управления можно увидеть в панели инструментов Visual Studio 2010. Связанные элементы управления группируются вместе по специфически именованным вкладкам.

По правде говоря, существуют два разных набора инструментов веб-элементов управления, поставляемых с . В дополнение к веб-элементам управления (внутри пространства имен System. Web. UI. HtmlControls) библиотеки базовых классов также предлагают виджеты System. Web. UI. HtmlControls.

Элементы управления HTML— это коллекция типов, позволяющих использовать традиционные элементы управления HTML на странице веб-формы. Однако в отличие от простых дескрипторов HTML, эти элементы являются объектно-ориентированными сущностями, которые могут быть сконфигурированы для запуска на сервере и потому поддерживают обработку событий серверной стороны. В отличие от веб-элементов управления , элементы HTML довольно просты по своей природе и предлагают меньше функциональности помимо стандартных дескрипторов HTML (HtmlButton, HtmlInputControl, HtmlTable и т. д.). Как и можно было ожидать, Visual Studio 2010 предлагает отдельный раздел панели инструментов для типов элементов управления HTML.

Элементы управления HTML предлагают общедоступный интерфейс, который имитирует стандартные атрибуты HTML. Например, для получения информации из области ввода используется свойство Value вместо принятого у веб-элементов свойства Text.

Учитывая, что элементы управления HTML не столь богато оснащены, как веб-элементы управления , далее они не рассматриваются.

Учитывая, что очень много «простых» элементов управления выглядят и ведут себя подобно своим аналогам из Windows Forms, детали базовых виджетов (Button, Label, TextBox и т. д.) также подробно рассматриваться не будут. Вместо этого проиллюстрируем работу с некоторыми из наиболее экзотичных элементов управления, а также моделью мастер-страницы и механизмом привязки данных.

Использование мастер-страниц

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

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

Кроме того, страница *.master определяет различные области-заполнители содержимого, которые устанавливают область пользовательского интерфейса, куда могут подключаться другие файлы *.aspx. Те, что включают свое содержимое в мастер-файл, выглядят и ведут себя несколько иначе, чем те файлы *.aspx, которые рассматривались до сих пор. В частности, файлы *.aspx этого типа называются страницами содержимого (content page). Страницы содержимого— это файлы *.aspx, которые не определяют HTML-элемента <form> (это задача для мастер-страницы).

Однако с точки зрения конечного пользователя запрос выполняется к заданному файлу *.aspx. На веб-сервере соответствующие файлы *.master и *.aspx смешиваются вместе — в единую унифицированную страницу.

Начальная разметка файла Site. Master выглядит следующим образом:

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site. master. cs" Inherits="WebApplication1.SiteMaster" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www. w3.org/TR/xhtml1/DTD/xhtml1-strict. dtd">

<html xmlns="http://www. w3.org/1999/xhtml" xml:lang="en">

<head runat="server">

<title></title>

<link href="~/Styles/Site. css" rel="stylesheet" type="text/css" />

<asp:ContentPlaceHolder ID="HeadContent" runat="server">

</asp:ContentPlaceHolder>

</head>

<body>

<form runat="server">

<div class="page">

<div class="header">

<div class="title">

<h1>

My Application

</h1>

</div>

<div class="loginDisplay">

<asp:LoginView ID="HeadLoginView" runat="server" EnableViewState="false">

<AnonymousTemplate>

[ <a href="~/Account/Login. aspx" ID="HeadLoginStatus" runat="server">Log In</a> ]

</AnonymousTemplate>

<LoggedInTemplate>

Welcome <span class="bold"><asp:LoginName ID="HeadLoginName" runat="server" /></span>!

[ <asp:LoginStatus ID="HeadLoginStatus" runat="server" LogoutAction="Redirect" LogoutText="Log Out" LogoutPageUrl="~/"/> ]

</LoggedInTemplate>

</asp:LoginView>

</div>

<div class="clear hideSkiplink">

<asp:Menu ID="NavigationMenu" runat="server" CssClass="menu" EnableViewState="false" IncludeStyleBlock="false" Orientation="Horizontal">

<Items>

<asp:MenuItem NavigateUrl="~/Default. aspx" Text="Home"/>

<asp:MenuItem NavigateUrl="~/About. aspx" Text="About"/>

</Items>

</asp:Menu>

</div>

</div>

<div class="main">

<asp:ContentPlaceHolder ID="MainContent" runat="server"/>

</div>

<div class="clear">

</div>

</div>

<div class="footer">

</div>

</form>

</body>

</html>

Первое, что здесь представляет интерес — директива <%@Master%>. В основном эта директива поддерживает те же атрибуты, что и директива <%@Раge%>, описанная выше. Подобно типам Page, мастер-страница наследуется от определенного базового класса, которым в данном случае является SiteMaster. Если мы откроем соответствующий файл кода, то увидим там следующее определение класса:

public partial class SiteMaster : System. Web. UI. MasterPage

{

protected void Page_Load(object sender, EventArgs e)

{

}

}

Другой интересный момент в разметке мастер-страницы— это тип <asp: ContentPlaceHolder> В эту область мастер-страницы подключаются виджеты пользовательского интерфейса связанного файла содержимого *.aspx, а не содержимое, определенное самой мастер-страницей.

Если мы намерены смешать файл *.aspx с этой областью, контекст внутри дескрипторов <asp:ContentPlaceHolder> и </asp:ContentPlaceHolder> будет пуст. Однако если мы поступим так, то сможем наполнить эту область различными веб-контролами, которые функционируют как пользовательский интерфейс по умолчанию, если заданный файл *.aspx не предоставит специфического содержимого.

поставляется с несколькими веб-элементами управления, которые позволяют выполнять навигацию по сайту: SiteMapPath, TreeView и Menu. Эти веб-виджеты могут быть сконфигурированы различными способами. Например, каждый из этих контролов может динамически генерировать свои узлы через внешний файл XML (или файл *. sitemap на базе XML), это можно делать программно в коде или через разметку, используя дизайнеры среды Visual Studio 2010. Наша система меню будет наполняться динамически через файл *. sitemap. Преимущество такого подхода состоит в том, что можно определить общую структуру нашего веб-сайта во внешнем файле и затем привязать его к виджету Menu (или TreeView) на лету. Таким образом, если навигационная структура веб-сайта изменится, достаточно будет просто модифицировать файл *. sitemap и перегрузить страницу. Добавление этого элемента на сайт средствами VisualStudio делается достаточно просто (Меню Project -> AddNewItem -> SiteMap).

Файл Web. sitemap определяет элемент самого верхнего уровня с двумя подузлами:

<?xml version="1.0" encoding="utf-8" ?>

<siteMap xmlns="http://schemas. /AspNet/SiteMap-File-1.0" >

<siteMapNode url="" title="" description="">

<siteMapNode url="" title="" description="" />

<siteMapNode url="" title="" description="" />

</siteMapNode>

</siteMap>

Если привязать эту структуру к элементу управления Menu, отобразится меню верхнего уровня с двумя подменю. Таким образом, когда мы захотим определить подменю, достаточно просто определить новые элементы <siteMapNode> в контексте существующего <siteMapNode>. Каждый из этих элементов может определять атрибут — заголовок и атрибут URL. Атрибут URL представляет файл *.aspx для навигации, когда пользователь щелкнет на заданном пункте меню (или узле TreeView). Сайт содержит три подэлемента, которые установлены следующим образом:

Hоmе (Домой): Default. aspx


Say Kykyreky (Сказать Кукуреку): SayKykyreky. aspx

View Mumu (Просмотреть коровник): CowHouse. aspx

Система меню имеет единственный элемент верхнего уровня Welcome (Добро пожаловать) с тремя подэлементами. Модифицируем файл Web. sitemap следующим образом (каждое значение url должно быть уникальным; в противном случае возникнет ошибка времени выполнения).

Теперь, несмотря на то, что можно было подумать, файл Web. sitemap не ассоциируется непосредственно с элементами Menu или TreeView, используя заданное свойство. Вместо этого файл *.master или *.aspx, содержащий виджет пользовательского интерфейса, который отобразит файл Web. sitemap, должен содержать компонент SiteMapDataSource. Этот тип автоматически загрузит файл Web. sitemap в свою объектную модель по запросу страницы. Экземпляры классов Menu и TreeView затем должны установить свои свойства DataSourcelD так, чтобы они указывали на экземпляр SiteMapDataSource.

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

Для добавления нового SiteMapDataSource к файлу *.master и установки свойства DataSourcelD можно использовать дизайнер Visual Studio 2010.

В результирующем диалоговом окне мы должны выбрать пиктограмму SiteMap. Это установит свойство DataSourcelD элемента Menu, а также добавит компонент SiteMapDataSource на страницу. Это все, что понадобится сделать, чтобы сконфигурировать виджет Menu для навигации к дополнительным страницам сайта. Если мы захотим выполнить дополнительную обработку при выборе пользователем пункта меню, можете сделать это, обработав событие MenuItemClick.

Следующий набор элементов управления Web Form, который мы рассмотрим, известен под названием элементы управления с проверкой достоверности (или валидации) – validation controls. В отличие от других элементов управления Web Forms, элементы с проверкой достоверности не используются для генерации HTML в целях визуализации, но применяются для генерации кода JavaScript клиентской стороны (и, возможно, связанного с ним кода серверной стороны) в целях проверки достоверности формы. Проверка достоверности форм клиентской стороны довольно удобна в том, что можно на месте проверять данные на соответствие различным ограничениям, прежде чем посылать их обратно на веб-сервер, тем самым сокращая дорогостоящий трафик. В таблице дана краткая сводка контролов с проверкой достоверности .

Все контролы так или иначе являются наследниками одного общего базового класса по имени System. Web. UI. WebControls. BaseValidator и потому обладают набором общих средств. В таблице документированы ключевые элементы классов контролов валидации.


Чтобы проиллюстрировать работу с этими контролами валидации, создадим новый проект WebApplication по имени ValidatorCtrls. Для начала поместим на страницу четыре именованных элемента типа TextBox. Затем поместим элементы типов RequiredFieldValidator, RangeValidator, RegularExpressionValidator и CompareValidator рядом с каждым соответствующим полем. И, наконец, добавим один элемент Button и один Label. Теперь, имея пользовательский интерфейс, давайте пройдемся по процессу настройки каждого элемента.


Конфигурирование RequiredFieldValidator осуществляется просто. Для этого соответствующим образом мы должны установить свойства ErrorMessage и ControlToValidate в Visual Studio.

Вот результирующая разметка, проверяющая, что текстовое поле TextBox1 не является пустым:

<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"

ControlToValidate="TextBox1" ErrorMessage="Ай-я-я-яй, это обязательное поле">

</asp:RequiredFieldValidator>

RequiredFieldValidator поддерживает свойство InitialValue. Его можно использовать для проверки того, что пользователь ввел какое-то значение, отличное от начального, в соответствующем TextBox. Например, когда пользователь впервые получает страницу, можно конфигурировать TextBox, чтобы он содержал значение "Введите имя". Теперь, если не установить свойство InitialValue элемента RequiredFieldValidator, исполняющая система решит, что значение " Введите имя" является корректным. Таким образом, чтобы гарантировать, что в TextBox введено правильное значение, только если оно не совпадает с "Введите имя", можно настроить виджет следующим образом:

<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"

ControlToValidate="TextBox1" ErrorMessage="Ай-я-я-яй, это обязательное поле"

InitialValue="Введите имя"></asp:RequiredFieldValidator>

Тип RegularExpressionValidator может использоваться, когда необходимо наложить шаблон на символы, вводимые в заданном поле. Чтобы гарантировать ввод в заданном поле TextBox корректного почтового индекса Российской Федерации, виджет можно определить так:

<asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server"

ControlToValidate="TextBox3" ErrorMessage="Введите правильный почтовый индекс"

ValidationExpression="\d{6}"></asp:RegularExpressionValidator>

Здесь RegularExpressionValidator определяет свойство ValidationExpression. Если программист ранее не работал с регулярными выражениями, все, что следует знать для рассматриваемого примера — это то, что они используются для проверки соответствия строки определенному шаблону.

В нашем случае выражение "\d{6}" получает стандартный номер почтового индекса РФ в форме хххххх (где х— десятичная цифра).

Это конкретное регулярное выражение достаточно очевидно; однако предположим, что требуется проверить правильность URL в интернете. Корректное выражение для этого случая выглядит немного сложнее: "http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?". По счастью, при выборе свойства ValidationExpression в окне Properties доступен предварительно определенный список распространенных регулярных выражений (по щелчку на кнопке с тремя точками).

В дополнение к свойствам MinimumValue и MaximumValue, тип RangeValidator включает свойство по имени Туре. Если необходимо проверять пользовательский ввод на предмет вхождения в диапазон целых чисел, следует специфицировать тип Integer (это не является установкой по умолчанию):

<asp:RangeValidator ID="RangeValidator1" runat="server"

ControlToValidate="TextBox2" ErrorMessage="Число вне диапазона"

MaximumValue="10" MinimumValue="1" SetFocusOnError="True" Type="Integer"></asp:RangeValidator>

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

Элемент CompareValidator поддерживает свойство Operator:

<asp:CompareValidator ID="CompareValidator1" runat="server"

ControlToValidate="TextBox4" ErrorMessage="Введите число больше 5"

Operator="GreaterThan" Type="Integer" ValueToCompare="5"></asp:CompareValidator>

Учитывая, что предназначение контролов валидации состоит в сравнении значения в текстовом поле и другого значения с использованием бинарной операции, не удивительно, что свойство Operator может принимать такие значения, как LessThan, GreaterThan, Equal и NotEqual. Также ValueToCompare используется для указания значения, с которым нужно сравнивать.

Чтобы завершить код этой страницы, нужно обработать событие Click элемента Button и проинформировать пользователя об успешном прохождении логики проверки достоверности:

public partial class _Default : System. Web. UI. Page

{

protected void Page_Load(object sender, EventArgs e)

{

}

protected void Button1_Click(object sender, EventArgs e)

{

Label5.Text = "Данные успешно отправлены на сервер";

}

Теперь мы можем загрузить готовую страницу в браузер. Сначала мы не увидим какие-либо заметные изменения. Однако при попытке щелкнуть на кнопке Submit (Отправить) после ввода неверных данных появится сообщение об ошибке. После ввода правильных данных сообщение об ошибке исчезнет и произойдет обратная отправка.

Если мы взглянем на HTML-код, визуализированный браузером, то обнаружим, что контролы валидации генерируют функцию JavaScript клиентской стороны, которая использует специфическую библиотеку функций JavaScript (содержащуюся в файле WebUIValidation. js), автоматически загружаемую на пользовательскую машину. Как только валидация прошла, данные формы отправляются обратно на сервер, где исполняющая система выполняет ту же самую проверку еще раз на веб-сервере (просто чтобы удостовериться, что данные не были подделаны в пути).

Кстати, если запрос HTTP был прислан браузером, который не поддерживает JavaScript клиентской стороны, то вся проверка достоверности проходит на сервере.

Таким образом, программировать контролы валидации можно, не задумываясь о целевом браузере; возвращенная страница HTML передаст обработку ошибок на веб-сервер.

Альтернативная и/или дополнительная возможность валидации – использование компонента ValidationSummary.

До сих пор у нас была возможность поработать с многочисленными веб-контролами . Как мы видели, каждый из них предоставляет набор свойств (многие из которых унаследованы от System. Web. Ul. Webcontrols. WebControl), позволяющих устанавливать внешний вид и поведение этих элементов пользовательского интерфейса (цвет фона, размер шрифта, стиль рамки и т. п.). Конечно, на многостраничном веб-сайте принято определять общий внешний вид и поведение виджетов различных типов. Например, все TextBox должны поддерживать определенный шрифт, все Button — иметь общий вид, а все Calendar — ярко-синюю рамку. Очевидно, что было бы очень трудоемкой (и чреватой ошибками) задачей задавать одинаковые установки свойств для каждого виджета на каждой странице веб-сайта.

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

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

Однако поставляется с альтернативной технологией для определения общего пользовательского интерфейса, именуемой темами. В отличие от таблиц стилей, темы применяются на веб-сервере (а не в браузере) и могут использоваться как программно, так и декларативно. Учитывая, что тема применяется на веб-сервере, она имеет доступ ко всем серверным ресурсам веб-сайта. Более того, темы определяются написанием той же разметки, что и в любом файле *.aspx.

Веб-приложения могут определять любое количество "специальных" каталогов, один из которых — App_Theme. Этот единственный каталог может быть дальше разбит на подкаталоги, каждый из которых представляет одну из возможных тем веб-сайта. На рисунке показан один каталог App_Theme, содержащий три подкаталога, каждый из которых имеет набор файлов, образующих саму тему.


Как видно, в каждом из них содержится файл *.skin. Эти файлы определяют внешний вид и поведение различных веб-контролов. Однако это относится скорее к конфигурированию Web-приложений, и рассматривается далее в разделе 3.3.

В заключение отметим, что с веб-контролами, также как и с WinForm-контролами могут связываться данные (data binding).

Это делается в два шага:

1.  Сначала в свойстве DataSource, уже упоминавшемся выше, указывается источник данных.

2.  Затем непосредственно привязка.

Например, следующий код показывает, как отобразить имена всех известных цветов в контрол ListBox:

// Получение списка цветов.

string[] colorArray = Enum. GetNames(typeof(KnownColor));

lstBackColor. DataSource = colorArray;

lstBackColor. DataBind();

Типичным сценарием является написание подобного кода в методе Page_Load() страницы. Например, набор фруктов в выпадающем списке:

protected void Page_Load(object sender, EventArgs e)

{

// Создание и заполнение коллекции.

List<string> fruit = new List<string>();

fruit. Add("Kiwi");

fruit. Add("Pear");

fruit. Add("Mango");

fruit. Add("Blueberry");

fruit. Add("Apricot");

fruit. Add("Banana");

fruit. Add("Peach");

fruit. Add("Plum");

DropDownList1.DataSource = fruit;

this. DataBind();

}

3.3 Конфигурирование веб-приложений

Вспомним, что в файле *.skin задается внешность и поведение различных виджетов с использованием декларативного синтаксиса элементов управления . К сожалению, в IDE-среде не предусмотрена поддержка дизайнера файлов *. skin. Один способ сократить объем ввода состоит в добавлении к программе временного файла *.aspx (например, tmp. aspx), который может быть использован для построения пользовательского интерфейса виджетов с помощью дизайнера страниц.

Полученную в результате разметку может затем скопировать в файл *.skin. При этом, однако, в обязательном порядке нужно удалить атрибут ID каждого веб-контрола. Это имеет смысл, поскольку мы не определяем вид и поведение конкретного элемента Button, а всех элементов Button.

С учетом этого, разметка для BasicGreen. skin может выглядеть так, чтобы определять внешний вид и поведение по умолчанию для типов Button, TextBox и Calendar:

<asp:Button runat="server" BackColor="#80FF80"/>

<asp:TextBox runat="server" BackColor="#80FF80"/>

<asp:Calendar runat="server" BackColor="#80FF80"/>

Теперь определим вторую тему по имени CrazyOrange. Используя Solution Explorer, нужно выполнить щелчок вспомогательной кнопкой мыши на папке App_Theme и добавить новую тему по имени CrazyOrange. Это создаст новый подкаталог внутри папки AppTheme. Затем нужно выполнить щелчок вспомогательной кнопкой мыши на новой папке CrazyOrange в Solution Explorer и выберать в контекстном меню пункт Add New Item (Добавить новый элемент). В появившемся окне нужно добавить новый файл *.skin. Обновим файл CrazyOrange. skin, определив уникальный внешний вид и поведение для тех же веб-контролов. Например:

<asp:Button runat="serverM BackColor="#FF8000"/>

<asp:TextBox runat="server" BackColor="#FF8000"/>

<asp:Calendar BackColor="White" BorderColor="Black"

BorderStyle="Solid" CellSpacing="l"

Font-Names="Verdana" Font-Size="9pt" ForeColor="Black" Height="50px"

NextPrevFormat="ShortMonth" Width="30px" runat="server">

<SelectedDayStyle BackColor="#333399" ForeColor="White" />

<OtherMonthDayStyle ForeColor="#999999" />

<TodayDayStyle BackColor="#999999" ForeColor="White" />

<DayStyle BackColor="#CCCCCC" />

<NextPrevStyle Font-Bold="True" Font-Size="8pt" ForeColor="White" />

<DayHeaderStyle Font-Bold="TrueM Font-Size="8pt"

ForeColor=M#333333" Height="8pt" />

<TitleStyle BackColor=M#333399M BorderStyle="Solid"

Font-Bold="True" Font-Size="12pt"

ForeColor="White" Height="12pt" />

</asp:Calendar>

Теперь, когда сайт имеет несколько тем, возникает справедливый вопрос: как применить их к страницам? Как и можно было ожидать, существует несколько путей сделать это.

Если мы хотите обеспечить оформление каждой страницы сайта в одной и той же теме, проще всего обновить файл web. config. Откроем его и найдем элемент <pages> внутри контекста корневого элемента <system. web>.

Добавление атрибута темы к элементу <pages> гарантирует применение одной и той же темы ко всем страницам сайта. Естественно, значение атрибута должно быть именем одного из подкаталогов внутри App_Theme. Вот основное изменение:

<configuration>

<system. web>

<pages theme="BasicGreen">

</pages>

</system. web>

</configuration>

Если теперь добавить различные элементы Button, Calendar и TextBox к файлу Default. aspx и запустить приложение, каждый виджет получит пользовательский интерфейс темы BasicGreen. Если изменить значение атрибута темы нa CrazyOrange и снова запустить приложение, пользовательский интерфейс будет соответствовать определенному этой темой.

Темы также можно применять к отдельным страницам. Это может быть полезно в различных ситуациях. Например, возможно, файл web. config определяет тему для всего сайта; однако, необходимо назначить определенной странице другую тему. Для этого нужно просто обновить директиву <%@Раgе>.

Если для этого используется Visual Studio, то IntelliSense отобразит все доступные темы, определенные в папке Арр_Themes.

<%@ Page Language="C#" AutoEventWireup="true"

CodeFile="Default. aspx. сs" Inherits="_Default" Theme ="CrazyOrange" %>

Поскольку этой странице назначена тема CrazyOrange, а в файле Web. config специфицирована тема BasicGreen, то все страницы, кроме данной, будут визуализированы с темой BasicGreen.

Иногда может понадобиться определить набор возможных внешних видов для отдельного виджета. Например, предположим, что необходимо определить два возможных пользовательских интерфейса для типа Button внутри темы CrazyOrange. В этом случае можно различать каждый вариант внешнего вида с помощью свойства SkinID:

<asp:Button runat="server" ВаскСоlог="#FF8000"/>

<asp:Button runat="server" SkinID = "BigFontButton" Font-Size="0pt" BackColor="#FF8000"/>

Теперь, если есть страница, которая использует тему CrazyOrange, каждому элементу Button по умолчанию будет назначен неименованная обложка Button. Если необходимо иметь несколько разных кнопок в одном файле *.aspx, можно использовать «обложку» BigFontButton, просто специфицируя свойство SkinID в разметке:

<asp:Button ID="Button2" runat="server" SkinID="BigFontButton" Text="Button" /> <br />


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

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

По умолчанию новые веб-приложения Visual Studio снабжаются начальной веб-страницей, файлом Web. config и специальной папкой по имени App_Data (по умолчанию пустой). Веб-сайты могут содержать любое количество специфически именованных подкаталогов, каждый из которых имеет определенное значение для исполняющей системы . В таблице описаны эти «специальные подкаталоги».

В файл Web. config можно добавить установки, управляющие поведением веб-приложения во время выполнения. Веб-ориентированные конфигурационные файлы всегда называются Web. config (в отличие от конфигурационных файлов *.ехе, которые называются по имени соответствующей клиентской исполняемой программы).

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


Часть информации в этих разделах автоматически изменяется при проектировании веб-приложения. Например, в раздел appSettings могут попасть строки подключения к соответствующей СУБД. Часть информации может быть сравнительно легко изменена вручную, как например, при настройке тем, как показывалось выше.

3.4 Управление состоянием в

Выше упоминалось, что протокол HTTP является протоколом, не поддерживающим состояние. Это делает веб-разработку совершенно отличающейся от привычного процесса построения исполняемой сборки. Например, при разработке приложения Windows Forms можно иметь уверенность, что переменные-члены, определенные в классе-наследнике Form, будут существовать в памяти до тех пор, пока пользователь явно не остановит исполняемую программу.

Однако в мире Всемирной паутины мы не можем исходить из этого предположения. Чтобы удостовериться в этом, создадим новый веб-сайт по имени SimpleStateExample. Внутри файла отделенного кода начальной страницы *.aspx определите строковую переменную уровня страницы по имени userString.

public partial class _Default : System. Web. UI. Page

{

private String userString = "V_V_Putin";

protected void Button1_Click(object sender, EventArgs e)

{

userString = TextBox1.Text;

}

protected void Button2_Click(object sender, EventArgs e)

{

Label5.Text = userString;

}

}

Добавим две кнопки на страницу. Обработчик события Click серверной стороны для кнопки Button1 позволит пользователю присвоить переменной типа string значение, взятое из TextBox (по имени textBox1).

Обработчик события Click для кнопки Button2 отобразит текущее значение переменной внутри виджета Label по имени Label5 страницы.

Запустив это веб-приложение, мы обнаружите, что всякий раз, когда выполняется обратная отправка на веб-сервер (при щелчке на любой кнопке), значение строковой переменной userString устанавливается обратно в свое начальное значение "V_V_Putin", и потому текст Label не изменяется.

Чтобы сохранить значение строковой переменной userString между обратными отправками, мы должны записать это значение в переменную сеанса (session variable). Приведем необходимые изменения, которые понадобится внести в текущую страницу (у нас больше нет более закрытой переменной типа string, а потому можно вообще закомментировать ее или исключить ее из определения класса):

public partial class _Default : System. Web. UI. Page

{

// private String userString = "V_V_Putin";

protected void Button1_Click(object sender, EventArgs e)

{

Label5.Text = "Данные успешно отправлены на сервер";

Session["userString"] = TextBox1.Text;

}

protected void Button2_Click(object sender, EventArgs e)

{

Label5.Text = Session["userString"] as string;

}

}

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

• использование состояния представления ;

• использование состояния элемента управления ;

• определение переменных уровня приложения;

• использование объект кэша;

• определение переменных уровня сеанса;

• определение cookie-данных.

Единственное, что объединяет все эти подходы — это то, что каждый из них требует, чтобы данный пользователь находился в сеансе, а веб-приложение было загружено в память. Как только пользователь выходит (или отключается по тайм-ауту) из сайта (или веб-сайт останавливается), сайт опять становится не поддерживающим состояние.

Если мы хотите сохранить пользовательские данные на постоянной основе, для этого предлагает готовый программный интерфейс Profile API. Мы не будем рассматривать детали каждого из перечисленных подходов, а лишь некоторые.

В мы не обязаны вручную собирать и заново заполнять значениями виджеты HTML, потому что исполняющая система автоматически встраивает скрытое поле формы по имени __VIEWSТАТЕ, которое передается между браузером и определенной страницей. Данные, присвоенные этому полю, представляют собой закодированную методом Base64 строку, содержащую набор пар имя/значение, которые соответствуют значениям виджетов пользовательского интерфейса на странице.

Обработчик событий базового класса Init из пространства имен System. Web. UI. Page представляет собой сущность, ответственную за чтение входных значений из поля __VIEWSТАТЕ для наполнения соответствующих переменных-членов производного класса. Кроме того, непосредственно перед отправкой исходящего ответа запросившему браузеру, данные __VIEWSTATE используются для повторного наполнения виджетов формы, чтобы гарантировать появление текущих значений виджетов HTML в том виде, в каком они были перед предыдущей обратной отправкой.

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

Директива <%@Раgе%> имеет необязательный атрибут по имени EnableViewState, который по умолчанию установлен в true. Чтобы отключить это поведение, изменим директиву <%@Раgе%> следующим образом:

<%@ Page Language="C#" AutoEventWireup="true"

CodeFile="Default. aspx. cs" Inherits="_Default"

EnableViewState ="false" %>

Первое правило состояния представления состоит в том, что оно работает только тогда, когда есть виджеты, значения которых динамически генерируются кодом. Если жестко закодировать эти значения внутри тэгов <form> файлов *.aspx, то состояние этих элементов будет всегда запоминаться между обратными отправками, даже если установить для страницы EnableViewState в false.

Более того, состояние представления наиболее полезно, именно при динамическом наполнении виджета, который всегда должен заполняться при каждой обратной отправке. Например, это может быть GridView, наполняемый из базы данных. Если не отключить состояние представления для страниц, содержащих такие виджеты, то все их состояние будет записано в поле __VIEWSTATE. Учитывая, что сложные страницы могут содержать многочисленные веб-элементы управления , можно представить, насколько огромной станет эта строка. Когда нагрузка, связанная с циклом HTTP запрос/ответ становится очень большой, это может превратиться в проблему для веб-серверов, работающих по медленным соединениям. В подобных случаях можно получить более быструю реакцию, отключив состояние представления для страницы.

Если идея отключения состояния представления для всего файла *.aspx нам кажется слишком уж экстремальной, мы должны помнить, что каждый наследник базового класса System.Web.UI.Control наследует свойство EnableViewState, которое существенно упрощает задачу отключения состояния представления отдельно для каждого элемента управления:

<asp:GridView id="myExtraLargeDynamicallyFilledDataGrid" runat="server"

EnableViewState="false">

</asp:GridView>

В дополнение к свойству EnableViewState, класс System. Web. UI. Control предоставляет унаследованное свойство по имени ViewStatе. Оно обеспечивает доступ к типу System. Web. UI. StateBag, представляющему все данные, которые хранятся в поле __VIEWSTATE. Используя индексатор типа StateBag, можно встраивать специальную информацию в скрытое поле формы __VIEWSTATE, применяя пары имя/значение. Вот простой пример:

protected void btnAddToVS_Click(object sender, EventArgs e)

{

ViewState["CustomViewStateltem"] = "Some user data";

lblVSValue. Text = (string)ViewState["CustomViewStateltem"];

}

Поскольку тип System. Web. UI. StateBag спроектирован для операций с любым типом-наследником System. Object, когда мы обращаемся к значению по заданному ключу, то мы должны явно приводить его к правильному типу данных, лежащему в основе (здесь — к System. String). Имейте в виду, однако, что значения, помещенные в поле __VIEWSTATE, не могут быть объектом в буквальном смысле. В частности, допустимыми являются String, Integer, Boolean, ArrayList, Hashtable и массивы всех этих типов.

Поэтому, исходя из того, что страницы *.aspx могут заносить пользовательские фрагменты информации в строку __VIEWSTATE, возникает следующий вопрос: когда это может понадобиться? В большинстве случаев специальные данные состояния представления больше подходят для хранения специфичной для пользователя информации. Например, можно установить данные состояния представления, которые специфицируют, как пользователь желает видеть пользовательский интерфейс элемента GridView (например, критерий и порядок сортировки). Данные состояния представления не слишком подходят для хранения полной информации пользователя, такой как элементы корзины для покупок или кэшированных DataSet. Когда нужно хранить сложную информацию подобного рода, лучше иметь дело с данными сеанса или данными приложения.


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

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

В типы-наследники Page, как и тип HttpApplication, используют идентично именованные свойства (т. е. Application и Session), которые представляют лежащие в основе объекты типов HttpApplicationState и HttpSessionState.

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

Как можно предположить из названия, объект System. Web. Caching. Cache, доступный через свойство Context. Cache, позволяет определить объект, доступный всем пользователям со всех страниц в течение фиксированного периода времени. В его простейшей форме взаимодействие с кэшем выглядит точно так же, как взаимодействие с типом HttpApplicationState:

// Добавить элемент в кэш.

// Этот элемент «не устареет».

Context. Cache["SomeStringltem"] = "This is the string item";

// Получить элемент из кэша.

string s = (string)Context. Cache["SomeStringltem"]

Однако если мы заинтересованы в автоматическом обновлении (или удалении) данных уровня приложения, объект Cache мало чем поможет, поскольку можно использовать непосредственно тип HttpApplicationState.

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

Класс System. Web. Caching. Cache определяет лишь небольшое количество членов помимо индексатора типа. Например, метод Add() служит для вставки в кэш нового элемента, который еще не был определен (если указанный элемент уже существует, Add() ничего не делает). Метод Insert() также помещает элемент в кэш, однако если данный элемент определен, Insert() заменяет текущий элемент новым. Именно такое поведение чаще всего и нужно.

Далее упомянем о роли данных, специфичных для пользователя. Как упоминалось ранее, сеанс (session) — это нечто чуть большее, чем взаимодействие конкретного пользователя с веб-приложением, представленное объектом HttpSessionState.

Чтобы поддерживать информацию о состоянии для конкретного пользователя, типы-наследники HttpApplication и System. Web. UI. Page могут обращаться к свойству Session.

Классический пример необходимости поддерживать данные пользователя — корзина покупок. Если 100 человек зашли в онлайновый электронный магазин, для каждого из них поддерживается уникальный набор наименований товара, который он намерен приобрести.

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

// Добавить/извлечь переменную сеанса для текущего пользователя.

Session["DesiredFruitColor"] = "Green";

string color = (string) Session["DesiredFruitColor"];

Тип-наследник HttpApplication позволяет перехватить момент начала и конца сеанса через обработчики событий Session_Start и Session_End. Внутри Session_Start можно свободно создавать любые элементы данных, специфичные для пользователя, в то время как Session_End позволяет выполнять любую работу, которая может понадобиться при закрытии сеанса пользователя:

<%@ Application Language="C#" %>

void Session_Start(Object sender, EventArgs e)

{

// Новый сеанс! Требуется подготовка. . .

}

void Session_End(Object sender, EventArgs e)

{

// Пользователь вышел или отключен по таймауту. Выполнить необходимую очистку.

}

Класс HttpSessionState определяет ряд других интересных членов, помимо индексатора типа. Свойство SessionID возвращает уникальный идентификатор пользователя. Если мы хотим увидеть автоматически присвоенный идентификатор сеанса, то в обработчике события Load страницы можно использовать следующий код:

protected void Page_Load(object sender, EventArgs e)

{

lblUserID. Text = string. Format("Here is your ID: {0}", Session. SessionID);

}

Методы Remove() и RemoveAll() могут использоваться для очистки элементов пользовательского экземпляра HttpSessionState:

Session. Remove("SomeltemWeDontNeedAnymore");

Тип HttpSessionState также определяет набор членов, которые управляют политикой устаревания текущего сеанса. По умолчанию каждый пользователь имеет 20 минут отсутствия активности, прежде чем объект HttpSessionState будет разрушен. Поэтому, если пользователь входит в веб-приложение (и, следовательно, получает уникальный идентификатор сеанса), но не возвращается на сайт в течение 20 минут, то исполняющая система предполагает, что пользователь больше не заинтересован в сайте и уничтожает его данные сеанса. Период устаревания сеанса можно изменить, установив его для каждого пользователя через свойство Timeout. Наиболее подходящее место для этого — метод Session_Start():

void Session_Start(Object sender, EventArgs e)

{

// Каждый пользователь имеет 5 минут отсутствия активности.

Session. Timeout = 5;

Session["UserShoppingCartlnfо"] = new UserShoppingCart ();

}

Важно: если мы не хотим настраивать значение Timeout для каждого пользователя, можно изменить 20-минутное значение по умолчанию для всех пользователей через атрибут Timeout элемента <sessionState> внутри файла web.config.

Преимущество свойства Timeout состоит в возможности назначать специфический тайм-аут отдельно каждому пользователю. Например, предположим, что создано веб-приложение, которое позволяет пользователям платить дифференцированную плату за различные уровни членства. Скажем, что «блатные» пользователи должны иметь тайм-аут длительностью в один час, в то время как обычные — только 30 секунд.

Такая возможность вызывает вопрос: как запомнить специфическую для пользователя информацию (вроде текущего уровня членства) между визитами на сайт? Один возможный вариант ответа— использовать для этого HttpCookie.

Состояние представления и приложения, кэш, данные сеанса и cookie-наборы управляются более или менее сходным образом (через индексатор класса). Кроме того, тип HttpApplication часто используется для перехвата и реакции на события, возникающие во время жизни веб-приложения.

По умолчанию сохраняет данные сеанса, используя библиотеку *.dll, находящуюся в рабочем процессе (aspnet_wp. exe). Подобно любой другой *.dll, положительной стороной является предельно возможная скорость доступа к информации.

Однако минусом такого решения является то, что если AppDomain терпит крах, то все пользовательские данные разрушаются. Более того, когда данные состояния хранятся во внутрипроцессной *.dll, нет возможности взаимодействовать с сетевой веб-фермой (networked web farm; вариант с размещением сайта на нескольких веб-серверах). Это поведение по умолчанию записывается в элементе <sessionState> файла web.config, как показано ниже:

<sessionState

mode="InProc"

stateConnectionString="tcpip=127.0.0.1:5562"

sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"

cookieless="false"

timeout="20"

/>

Такой режим хранения по умолчанию работает достаточно хорошо, если веб-приложение развернуто на единственном веб-сервере. Однако, как можно предположить, подобная модель не идеальна для фермы веб-серверов, учитывая, что состояние сеанса «захватывается» определенным AppDomain.

В можно также указать исполняющей системе на необходимость развернуть *.dll состояния сеанса в суррогатном процессе, именуемом сервером состояния сеансов (aspnet_state.ехе). При этом можно перегрузить * .dll из aspnet_wp. ехе в отдельный *.ехе, который может находиться на любой из машин веб-фермы.

Даже если мы намерены запустить процесс aspnet_wp. exe на той же машине, что и веб-сервер, мы выигрываем от выделения данных состояния в отдельный процесс, т. е. это более надежно.

Чтобы использовать сервер состояния сеансов, сначала нужно запустить Windows-службу aspnet_state. exe на целевой машине. В командной строке:

net start aspnet_state

В любом случае, как только сервер состояния сеансов запущен, добавим элемент <sessionState> в файл web. config следующим образом:

<sessionState

mode="StateServer"

stateConnectionString="tcpip=127.0.0.1:5562"

sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"

cookieless="false"

timeout="20"

/>

И, наконец, если требуется максимальная степень изоляции и надежности веб-приложения, можно заставить исполняющую систему хранить все данные о состоянии сеанса внутри Microsoft SQL Server. Необходимое для этого изменение файла web. config очень простое:

<sessionState

mode="SqlServer"

stateConnectionString="tcpip=127.0.0.1:5562"

sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"

cookieless="false"

timeout="20"

/>

Однако, здесь мы получим проигрыш в производительности.

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

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

Чтобы помочь справиться с такими ситуациями, поставляется с готовым API-интерфейсом управления профилями пользователей и соответствующей базой данных. В дополнение к обеспечению необходимой инфраструктуры, Profile API также позволяет определить данные, которые должны храниться непосредственно в файле web. config (для упрощения); однако можно хранить и любой тип, помеченный как [Serializable].

Для того чтобы использовать профили нам нужно выполнить следующие шаги:

1. Создать таблицы профилей. Но если мы используем SQL Server Express Edition, то таблицы будут создаваться автоматически.

2. Сконфигурировать провайдер профилей.

3. Определить некоторые свойства профилей.

4. Включить аутентификация для части нашего веб-сайта.

5. Использовать свойства профилей в коде нашей страницы.

Итак, если мы не используем SQL Server Express, мы должны создать таблици профилей вручную. Для это мы используем утилиту командной строки aspnet_regsql.exe, т. е. тем же инструментов, который позволяет нам генерировать базы данных для других возможностей, предоставляемых . Подробнее, см. выше.

Эта утилита расположена в каталоге c:\Windows\\Framework\[Version] folder.

Для создания таблиц, представлений и хранимых процедур, мы должны запустить aspnet_regsql.exe с опциями -A p. Единственное, что нам нужно обеспечить еще, это расположение сервера (-S), имя базы данных (-d), и информация для подключения к базе (-U и - P для указания пользовательского имени и пароля; либо -E – для текущей учетной записи Windows). Если мы не укажем конкретный сервер и имя базы, то aspnet_regsql.exe будет использовать текущую машину и создаст базу по имени aspnetdb.

Вот простой пример создания базы aspnetdb на текущем компьютере с использованием параметров текущей учетной записи Windows:

aspnet_regsql. exe - A p - E

После подготовки нашей базы данных, мы можем зарегистрировать SqlProfileProvider в файле web.config. Сначала определяется строка подключения к базе данных с профилями. Затем используется раздел <profile>, чтобы удалить все существующие провайдеры (элемент <clear>), и добавляется новый экземпляр класса System. Web. Profile. SqlProfileProvider (элемент <add>). Вот установки конфигурации, которые нам нужны для приложения по имени ShoppingCart:

<configuration>

<connectionStrings>

<add name="SqlServices" connectionString=

"Data Source=localhost;Integrated Security=SSPI;Initial Catalog=aspnetdb;" />

</connectionStrings>

<system. web>

<profile defaultProvider="SqlProvider">

<providers>

<clear />

<add name="SqlProvider"

type="System. Web. Profile. SqlProfileProvider"

connectionStringName="SqlServices"

applicationName="ShoppingCart" />

</providers>

</profile>

...

</system. web>

</configuration>

Когда мы определили провайдера профилей, мы должны указать название (к нему элемент <profile> может впоследствии ссылатьяс как к провайдеру по умолчанию (default provider)), точное имя типа, строка полключения и имя веб-приложения.

Затем мы должны описать пользовательский профиль в файле web. config. С этим профилем можно взаимодействовать в строго типизированной манере, используя унаследованное свойство Property. Чтобы проиллюстрировать это, создайте новый веб-сайт по имени WorkWithProfiles и откройте файл web. config для редактирования.

Нашей целью будет создание профиля, который моделирует домашний адрес пользователей, находящихся в сеансе, а также общее количество их обращений к этому сайту. Не удивительно, что данные профиля определяются внутри элемента <profile> с использованием множества пар типа имя/значение. Рассмотрим следующий профиль, созданный в контексте элемента <system. web> (информация, подобная приводившейся в предыдущем код, опущена):

<profile>

<properties>

<add name="Street" type="System. String" />

<add name="City" type="System. String" />

<add name="Region" type="System. String" />

<add name="TotalPost" type="System. Int32" />

</properties>

</profile>

Здесь мы специфицировали имя и тип данных CLR для каждого элемента профиля. Строго говоря, атрибут типа не обязателен; однако по умолчанию принят System. String. Cуществует много других атрибутов, которые могут быть специфицированы в единице профиля для дальнейшего уточнения способа хранения этой информации в ASPNETDB. mdf.

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

Рассмотрим следующее изменение:

<profile>

...

<properties>

<group name ="Address">

<add name="Street" type="String" />

<add name="City" type="String" />

<add name="Region" type="String" />

</group>

<add name="TotalPost" type="Integer" />

</properties>

...

</profile>

Здесь мы определили специальную группу по имени Address, включающую название улицы, город и регион пользователя. И теперь, чтобы обратиться к данным со страниц, потребуется код с указанием Profile.Address для доступа к каждому подэлементу.

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

<configuration>

...

<system. web>

<authentication mode="Windows"/>

<authorization>

<deny users="?"/>

</authorization>

...

</system. web>

</configuration>

Когда мы с этим покончим, можно получать доступ к информации о прфиле с использованием свойства Profile текущей страницы. Когда пользователь запустит приложение, тогда создаст новый класс для представления профиля путем наследования от System.Web.Profile.ProfileBase, который является оберткой для коллекции установок профиля. добавляет строго типизированное свойство к этому классу для какдого свойства профиля, которое мы определели в файле web.config. Эти строго типизированные свойства просто вызывают статические меттоды GetPropertyValue() и SetPropertyValue() базового класса ProfileBase, чтобы прочесть или установить соответствующие значения полей профиля.

Например, если мы определили строковое свойство по имени Street, то мы можем дать ему значение в коде для страницы:

Profile. Street = "Проспект Мира";

Использованные источники

1.  Ajax – http://msdn. /ru-ru//gg454710.aspx

2.  MVC – http://msdn. /ru-ru//gg430455.aspx

3.  Profile Properties Overview – http://msdn. /en-us/library/2y3fs9xs. aspx

4.  WebForms – http://msdn. /ru-ru//gg404476.aspx

5.  MacDonald, M. Pro in C# 2010, Fourth Edition. / M. MacDonald, A. Freeman, M. Szpuszta. – Apress, 2010. – 1614 p.

6.  Shepherd, G. Microsoft 4Step by Step. / G. Shepherd. – Microsoft Press, 2010. – 620 p.

7.  The Official Microsoft Site – http://www.

8.  Макки, А. Введение в NET 4.0 и Visual Studio 2010 для профессионалов. / А. Макки. - М.: "", 2010. — 416 с.

9.  Программирование на - http://www. *****/department/internet/praspnet/

10.  Троелсен, Э. Язык программирования С# 2008 и платформа. NET 3.5, 4-е изд. / Э. Троелсен. — М.: "", 2010. — 1344 с.

11.  Шилдт, Г. С# 3.0: полное руководство. / Г. Шилдт. — М.: "", 2010. — 992 с.