Что в этой статье?
Данная статья описывает базовые знания и наиболее полезные и удобные возможности ASP.NET. После ее прочтения вы будете в состоянии создавать сайты средней сложности.
Для кого эта статья?
Я рассчитывал на .NET разработчиков, знакомых с языком C# и HTML. Эта статья должна стать отправной точкой в изучении ASP.NET.
Hello World
Итак, начнем с создания простейшего приложения. Если у вас еще не установлен IIS 7.0 (Internet Information Services), то обратитесь к своему любимому поисковику и скачайте.
Для начала надо зарегистрировать сайт. У сайта должен быть физический каталог, где будут храниться все его файлы. Создать его можно где угодно, но желательно в папке C:\Inetpub\wwwroot (где С: - диск, на ктором стоит WIndows). Это позволит избежать неприятностей с правами. Далее заходим в Панель управления -> Администрирование ->Диспетчер служб IIS.

Разворачиваем дерево слева, щелкаем правой кнопкой по Defaul Web Site и выбираем Добавить приложение.

В появившемся окне вводим псевдоним (это будет адрес сайта) и путь к директории, созданной на первом шагу.

Приготовления готовы, теперь можно взятся за сам сайт. Если вы не запаслись никаким редактором – не беда! Будем все делать в блокноте. Итак, открываем блокнот и пишем код простенькой страницы:
<%@ Page %>
<html>
HelloWorld!
</html>
|
Сохраняем файл в директорию сайта, с именем default.aspx. Теперь откройте свой браузер и в строке адреса наберите http://localhost/TestSite/default.aspx
Теперь, для разжигания интереса, давайте добавим немного кода.
<%@ Page %>
<script language=C# runat=server>
void Page_Load(object o, EventArgs e)
{
Response.Write("Вы открыли страницу " + System.DateTime.Now.ToString());
}
</script>
<html>
<br>
HelloWorld!
</html>
|
Как это работает
IIS
Первым шагом мы зарегистрировали приложение в IIS. Рассмотрим роль IIS в работе сайта.
Главной задачей IIS является принимать запросы, и перенаправлять их в приложения вроде нашего. IIS может работать не только с ASP.NET сайтами, он появился еще до возникновения .NET. При установке .NET Framework, в базе данных IIS регистрируется библиотека aspnet_isapi.dll, и ассоциируется с расширением aspx и некоторыми другими. Когда приходит запрос на файл с этим расширением, IIS вызывает фунцию из данной библиотеки, передавая обработку запроса в ее руки. Получив управление, код aspnet_isapi.dll перенаправляет запрос в специальный .NET поток. На этом роль IIS обработке запроса оканчивается.

.NET процесс
При попадении в .NET процесс, запрос пакуется в объект HttpContext. Далее создается объект HttpApplication (возможно использование объекта оставшегося с прошлого запроса), в котором будут храниться информация о запросе, состояние сеанса, состояние приложения, информация о сервере и некоторая другая полезная информация. В классе HttpApplication определено множество событий, реагировать на которые мы можем создав файл Global.asax. После, управление передается классу PageHandlerFactory. Если сайт неоткомпилирован, он компилируется, далее создается объект-страница, который и формирует ответ.

Формат aspx-страниц
Начинается страница с тега Page
У него есть множество параметров, которые мы рассмотрим по мере изучения.
Далее идет html код. В нем мы можем использовать .NET элементы управления, определенные в пространстве имен System.Web.UI.WebControls. Делается это примерно таким образом
<asp:Button runat=”server” ID=”MyButton” Text=”PressMe” />
|
То есть к имени класса приписываем “asp:” и обязательно добавляем атрибут runat=server. Без этого атрибута при компиляции элемент не будет распознан как Button, а просто текст этого тега запишется в ответ. Кстати, в будующем классе для каждого контрола определяется поле, с именем указанов в атрибуте ID. Например к нашей кнопке можно будет обратиться так:
MyButton.Text = “NewText”;
|
По принципу как я определил атрибут Text, можно задать любое свойство или поле, определенное в классе Button.
Исполняемый код
Вся наша страница, в конечном счете, превратится в определение класса, производного от Page. Мы можем указать собственный базовый класс добавив атрибут к тегу Page:
<%@ Page Inherits=”MyBasePageClass” %>
|
Этот класс может быть определен в библиотеке dll, помещенной в подкаталог bin основной директории сайта, или в .cs файле, который также надо указать в теге Page:
<%@ Page CodeFile=”MyBasePageClassDefinition.cs” Inherits=”MyBasePageClass” %>
|
Кроме того, можно определить методы будущего класса напрямую, исползуя тег script:
<script runat=server language=C# >
</script>
|
Имя класса можно указать в атрибуте ClassName тега Page:
<%@ Page ClassName=”MyPageClass” %>
|
Есть еще один способ внедрить код в страницу, самый простой. В любом месте страницы пишем код на языке указанном в атрибуте Language тега Page (кстати если указан этот атрибут, то можно не указывать его повторно в теге script) заключив его в <% %>:
<%@ Page Language=C# %>
<html>
<% Response.Wite(“Никогда не использовал этот метод (”); %>
</html>
|
Когда он будет взываться, понятия не имею, если узнаете, напишите плиз в коменте (.
События
В классе Page определено множество полезных событий. В ASP.NET есть способ подписаться на эти события, просто определив метод с особым именем. Особость этого имени заключается в том, что имеет вид Page_ИмяСобытия. Например, вот так будет выглядеть обработчик события Load:
<script runat=server language=C# >
void Page_Load(object sender, EventArgs
{
if(! IsPostBack)
InitializeControls();
}
</script>
|
Определить обработчики также можно в базовом классе, указанном в атрибуте Inherits.
На события элементов управления можно подписаться прямо при их объявлении:
<asp:Button runat=server ID=”MyButton” OnClick=”MyButtonClick” />
|
Объявить метод MyButtonClick можно либо в базовом классе, указанном атрибуте Inherits, либо в блоке script:
<script runat=server >
void MyButtonClick(object sender, EventArgs e)
{
MyButton.ForeColor = System.Drawing.Color.Blue;
}
</script>
|
Register – что-то вроде using
Если вы определили собственные WebControl'ы или хотите использовать элементы управления стронних производителей, то поместите dll-билиотеку в папку bin, а в aspx странице в начале укажите тег Register:
<%@ Register Assembly="MyDll.dll" Namespace=”MyNamespace” TagPrefix="cc1" %>
|
Теперь элементы управления из библиотеки MyDll.dll можно использовать так:
<cc1:MySuperControl runat=server ID=CoolControl />
|
Шаблоны страниц
Этот термин придумал я, а речь, по сути, пойдет об использовании контрола ControlPlaceHolder. Я выделил это в отдельный раздел, так как считаю эту тему очень важной. Она намного упрощает создание сайта, в котором множество страниц имеют общие черты (напр шапку, панель навигации…).
Итак, выдлеяем общие черты у страниц, и код выносим в отдельный файл с расширением master. В начале тег Page заменяем тегом Master:
В местах, где у страниц будет специфичный контент, добавляем примерно такой тег:
<asp:ControlPlaceHolder runat=server id=SpecificContent1 />
|
Чтобы применить этот шаблон к странице делаем следующее. В теге Page указываем атрибут MasterPageFile:
<%@ Page MasterPageFile=”MyMasterPageFile.master” %>
|
Теперь осталось заполнить специфичный контент, соотвествующий данной странице. Это делается посредством определения тега Content с атрибутом ControlPlaceHolderID – ID того ContentPlaceHolder’а, на месте которого мы хотим вставить данный контент.
<asp:Content runat=server ContentPlaceHolderID=”SpecificContent1” >
This is specific content
<asp:Button runat=server Text=SomeButton />
</asp:Content>
|
Готово! Теперь, чтобы изменить внешний вид всех страниц сайта, достаточно отредактировать один файл!
Состояние сеанса
При общении программы с определенным пользователем, наверняка нужно будет хранить какие-то данные на протяжении всего диалога (например его имя). Для этого в классе Page имеется свойство Session типа HttpSessionState. Оно хранит коллекцию пар имя-объект. Вот так можно положить значение в коллекцию:
Session[“UserName”] = textBox1.Text;
|
А вот так читать:
label1.Text = (string) Session[“UserName”];
|
Хранить можно объекты любого типа. Значения хрантся 20 мин с прихода последнего запроса. Настроить это можно добавив в файл web.config следующее:
<SessionState timeout=77>
|
где 77 – произвольное число минут. Максимальное значение 1 год. Но ставить большие значения в данный параметр бессмысленно, не изменив еще один параметр. Дело в том, что по умолчанию коллекция Session хранится в динамической памяти потока (в куче). Иными словами, при перезагрузке сервера все данные будут утеряны. Чтобы этого избежать добавляем атрибут mode к тегу SessionState:
<SessionState timeout=1000 mode=SQLServer >
|
Возможные значения атрибута mode:
InProc – по умолчанию, в куче, уже обсуждалось
StateServer – в отдельном процессе. Позволяет сохранять данные при перезапуске приложения.
SQLServer – в базе данных. Медленнее, однако, гарантированна сохранность данных.
off – отключена. Если вы не используете Session, то имеет смысл отключить эту функциональность, чтобы она не замедляла работу.
Как это работает
При поступлении запроса создается новая коллекция. Ей присваивается уникальный индетификатор. Далее этот индитификатор сохраняется в виде сookie у клиента. Так запросы от одного пользователя объединяются в один сеанс. Можно настроить сохранение индетификатора сеанса через url вместо использования сookie. При этом способе к url добавляется параметр – id сеанса. Для включения этого режима добавляем атрибут cookieless:
<SessionState coockieless=true >
Напомню, этот тег нужно добавлять в файл web.config.
Автоматическая проверка ввода
В .NET есть элементы управления, позволяющие генерировать JavaScript код по проверке введенных пользователем значений. При попытке браузера отправить данные на сервер (например при нажатии кнопки), значения элементов управления проверяются, и если они не проходят проверку, то отправка формы не осуществляется, а на месте, где был опререлен проверщик становится видимым текст, информирующий пользователя. Существует несколько таких проверщиков:
<asp:RequiredFieldValidator ControlToValidate=textBox1
Text =”Пользователь, введите значение в textBox1” runat=server />
|
Проверяет, введено ли какое либо значение в textBox1 в данном случае. textBox1 – ID элемента управления.
<asp:CompareValidator ControlToValidate=textBox1 ControlToCompare=textBox2
Text =”Значения textBox1 и textBox2 не равны!” runat=server />
|
Сравнивает значения textBox1 и textBox2.
<asp:RegularExpressionValidator ValidationExpession=”*@*.* “ ControlToValidate=textBox1
Text =”Значение не имеет вид smth@smth.smth” runat=server />
|
Проверяет значение на соответсвие регулярному выражению.
<asp:RangeValidator MinValue=1 MaxValue=10 ControlToValidate=textBox1
Text =”Значение не лежит в диапазоне от 1 до 10” runat=server />
|
Проверяет, попадает ли значение в определенный диапозон
<asp:ValidatoinSummary HeaderText=”Некторые из обязательный полей не заполненны:” runat=server />
Этот проверщик требует более подробного описания. Его задача – сообщать суммарную информацию о неправильном вводе. Иными словами, он собирает информацию со всех других проверщиков. Для корректной работы ValidationSummary, во всех других проверщиках должно быть задано свойство ErrorMessage. Эти сообщения будут выводиться в виде списка, под HeaderText. например, допустим на странице имеются два таких проверщика:
<asp:RequiredFieldValidator ErrorMessage=”Не введено значение в textBox1”
ControlToValidate=textBox1 runat=server />
<asp:RequiredFieldValidator ErrorMessage=”Не введено значение в textBox2”
ControlToValidate=textBox2 runat=server />
|
Если оба поля будут пустыми, то ValidationSummary выведет следующее:
Некторые из обязательных полей не заполненны:
- Не введено значение в textBox1
- Не введено значение в textBox2
Как видите, первая строчка – HeaderText, а дальше перечисляются значения ErrorMessage сработваших проверщиков страницы.
<asp:CustomValidator OnServerValidate=”MyCallBack” ControlToValidate=”textbox1” Text=”Значение недопустимо…” />
|
Это чисто серверный проверщик. Он позволяет определить вам свою функцию, которая будет проверять правильность ввода данных. Вот так должна выглядеть callback функция:
void MyCallBack(object sender, ServerValidateEventArgs args)
{
if (args.Value != ”ControlValue”)
args.IsValid=false;
}
|
MyCallBack – это имя заданное в атрибуте OnServerValidate.
Ускоряем сайт – кэширование страниц
Вероятно, ваше приложение будет генерировать одну и ту же траницу пока не сменятся определенные условия. ASP.NET позволяет за счет этого ускорить работу приложения. Один раз формируется ответ, сохраняется, и этот готовый html возвращается на все запросы. Условиями могут быть истечение промежутка времени, изменение значений элементов управления, параметров и заголовков запроса.
Чтобы применить данную возможность к странице добавляем в начало тег СacheOutput:
<%@ CacheOutput
Duration=10
VaryByParam=param
VaryByControl=textbox1
VaryByHeader=header
VaryByCustom=browser %>
|
Атрибуты (обязательный только Duration) задают условия, при смене которых страница будет поновой формироваться.
Duration
Время в секундах, по истечении которого кэш станет недействительным.
VaryByControl
ID элемента управления, при смене заначения которого кэш станет недействительным.
VaryByHeader
Имя заголовка запроса, при изменении значения которого кэш станет недействительным.
VaryByParameter
Имя параметра запроса, при изменении значения которого кэш станет недействительным.
VaryByCustom
Позволяет программисту определить действительность кэша. Для этого надо переопределить метод GetVaryByCustomString в файле global.asax. Вот примерное содержимое файла:
<%@ Application language=C# %>
public virtual string GetVaryByCustomString(HttpContext context, string custom)
{
}
|
Значение атрибута VaryByCustom превратиться в парметр custom метода GetVaryByCustomString. Базовая реализация метода реагирует на значение параметра custom = “browser”. То есть для зарпосов, сделанных разными браузерами метод вернет разные строки, и страница будет поновой сформированна.
Послесловие
В данной статье я описал базовые знания и самые полезные и удобные возможности предоставляемые разработчику, создающему ASP.NET приложение. Функциональность ASP.NET на этом далеко не заканчивается. Удачи в дальнейшем изучении этой замечательной технологии!
Богатырев Павел (pfight at vestace.ru)
21.02.2009