Лекция 2. Анатомия ASP.NET. ASP.NET в действии.

ADO.NET – набор классов, предназначенных для доступа к базам данных Microsoft SQL Server, к источникам данных OLEDB и к файлам XML.

Введение

ASP.NET – один из компонентов .NET Framework. Перечислим кратко основные черты этой технологии.

* Общеязыковая исполнительная среда CLR
* Библиотека классов .NET Framework
* Языки.NET(C#, VB.NET, J# и другие)
* ADO.NET
* ASP.NET
* Web-службы
* Промежуточный язык MSIL (Microsoft Intermediate Language). Это ассемблер для среды выполнения CLR.

ADO.NET – набор классов, предназначенных для доступа к базам данных Microsoft SQL Server, к источникам данных OLEDB и к файлам XML.

Разные части вашего проекта могут быть написаны на разных языках, это называется interoperability. Мы попробуем написать проект, где одна из страниц будет на Visual Basic, а другая на С#.

Компютерные языки бывают компилируемыми и интерпретируемыми. В процессе компиляции программы, написанной на компилируемом языке, создается выполняемый файл(В Windows – exe). Он выполняется быстро, но не может исполняться на другой платформе. Машина, на которой она выполняется, должна иметь похожую конфигурацию. Например, если программа использует dll, то эта библиотека должна быть установлена и на целевой машине. Интерпретируемые программы компилируются в момент выполнения, поэтому они работают медленнее, но не зависят от конкретной машины. В .NET Framework применяется двухэтапная компиляция, то есть первый этап – это компиляция в MSIL, а вторая – компиляция «Just-in-time» компилятором во время исполнения. JIT-компилятор оптимизирует код для той машины, на которой он исполняется. В ASP.NET страница компилируется в MSIL при первом обращении клиента к странице. Вместе с ней компилируются классы, которые она использует. Если вы используете Visual Studio 2005, можно не ожидать первого запроса, а принудительно скомпилировать все страницы вашего проекта. Это позволит выявить синтаксические и другие ошибки.

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

Вы можете ознакомиться с проектом на сайте http://mono-project.com

На странице http://go-mono.com/archive/xsp-0.10.html находится XSP - сервер ASP.NET, который может служить расширением сервера Apache – основного сервера *nix – систем.

Как работает ASP.NET

Когда мы исталлируем .NET, в соответсвующих директориях C:WINDOWSMicrosoft.NETFramework помещается также файл aspnet_isapi.dll. Это – ISAPI-расширение, и предназначено оно для получения запросов, адресованных ASP.NET-приложениям (*.aspx *.asmx и т.д.), а также создания рабочих процессов aspnet_wp.exe, обратывающих запросы. Интернет-сервер – IIS или встроенный в WebMatrix или встроенный в Visual Studio Cassini – используют это расширение, когда им надо обработать обращение к страницам с расширением aspx.

Этот модуль разбирает(parse) содержимое страниц aspx вместе с файлом отделенного кода и генерирует класс на языке страницы с объектом Page. Страница aspx отличается от обычной HTML-страницы наличием серверных элементов управления, которые описываются специальными тегами. Для понимания работы ASP.NET важно отметить, что каждому тегу элемента управления соответствует свой член класса страницы. Например,

<asp:Label ID="Label1" runat="server"></asp:Label>

преобразуется в

@__ctrl = new global::System.Web.UI.WebControls.Label();

Основная задача объекта Page – посылка HTML-код в выходной поток. Этот класс компилируется в библиотеку .dll, которая загружается в процесс веб-сервера. Последующие запросы к странице также обрабатывает dll, если исходный код страницы не меняется. Все эти файлы можно найти в директории «Temporary ASP.NET Files» текущей версии .NET. Если мы работаем в среде разработки Visual Studio 2005 или VWD, для каждого проекта создается своя поддиректория.

Типы страниц и папок проекта

В проект можно добавлять новые файлы через диалог New File. Если снять отметку с флажка “Place code in separate file”, Visual Studio создаст один файл, в котором будет и страница, и код для ее обработки(в стиле WebMatrix).

Все файлы помещаются в директорию проекта. И наоборот, все файлы, которые будут помещены в директорию проекта, станут его частью. Для веб-сайтов не существует специального файла .csproj, в котором перечислялись бы его составные части, как это было в предыдущих версиях Visual Studio. Структура решения(solution) описывается в текстовом файле .sln. В решение могут входить несколько веб-сайтов и библиотек.

В ASP.NET 2.0 имеются специальные поддиректории проекта для разных типов файлов. Например, в папке App_Code хранятся общедоступные классы, текстовые файлы и некоторые другие(DataSet, диаграмма классов). Файлы с расширениями .cs или .vb, попавшие туда, автоматически компилируются, когда запрашивается любая страница проекта. В App_Data содержатся источники данных, используемых в проекте – базы данных Access и Microsoft SQL, XML-файлы. К этой директории нельзя получить доступ извне, а только из самого приложения. В папке Themes хранятся темы проекта(лекция 13). Применение тем позволяет настроить единообразный внешний вид сайта и централизованно им управлять. В App_GlobalResources находятся ресурсы, например таблицы строк, которые можно создавать на разных языках. Язык ресурсов выбирается автоматически в зависимости от настроек браузера пользователя. В папке App_WebReferences находятся ссылки на используемые веб-сервисы.

Можно создавать собственные поддиректории проекта, например, для хранения картинок.

Проект на 2 языках

Проект Web-сайта состоит из страниц aspx и классов, которые используются на страницах(и, конечно, разнообразных ресурсов). Файлы с классами, к которым можно обратиться из разных страниц, помещают в специальную папку App_Code. При компиляции они помещаются в одну сборку – библиотеку .dll в формате portable executable. Совершенно неважно, на каком языке написан класс, если это язык .NET.

Готовые скомпилированные сборки сторонних производителей тоже можно использовать в проекте. Их помещают в папку Bin. При этом их необходимо импортировать в проект.

<%@ Import Namespace="MyCustomNamespace" %>

Создайте новый проект. Добавьте в него файл, выбрав тип файла Class и язык Visual Basic. Среда сама предложит поместить его в папку Code. Назовем его CustomClass. У него будет очень простой код. Всего одна функция, которая добавляет слово Hello к имени, переданному в качестве параметра.

Imports Microsoft.VisualBasic
  Public Class CustomClass
      Public Function GetMessage(ByVal name As String) As String
          Return "Hello,  " & name
      End Function
  End Class

Добавьте в проект страницу CodeFolder_cs.aspx. Это страница написана на C#, но она создает класс, написанный на VB.NET.

<%@ page language="C#" %>
  <script runat="server">
    void Button1_Click(object sender, EventArgs e)
    {
      CustomClass c = new CustomClass();
      Label1.Text = c.GetMessage(TextBox1.Text);
    }
  </script>
  <html>
  <head>
      <title>ASP.NET Inline Pages</title>
  </head>
  <body>
      <form id="Form1" runat="server">
        <h1>Welcome to ASP.NET 2.0!</h1>
        <b>Enter Your Name:</b>
        <asp:TextBox ID="TextBox1" Runat="server"/>
        <asp:Button ID="Button1" Text="Click Me" OnClick="Button1_Click" Runat="server"/>
        <br />
        <br />
        <asp:Label ID="Label1" Text="Hello" Runat="server" />
      </form>
  </body>
  </html>

На странице определена форма, напоминающая форму Windows-приложения. На ней имеется кнопка, нажатие на которую обрабатывается в функции Button1_Click. В ней создается класс и вызывается его функция GetMessage с параметром, который берется из элемента редактирования. Возвращаемое значение записывается в элемент Label1. В более простом варианте это выглядит так:

Label1.Text = “Hello ”+TextBox1.Text;

Класс может быть написан на C#, а использоваться из страницы на Visual Basic.

using System;
  public class CustomClass2
  {
      public String GetMessage(String input) {
          return "Hello from C# " + input;
      }
  }
   Код страницы CodeFolder_vb.aspx:
  <script runat="server">
    Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
      Dim c As New CustomClass2
      Label1.Text = c.GetMessage(TextBox1.Text)
    End Sub
  </script>

Однако поместить в директории App_Code можно только на одном языке. Если там будет находиться файлы на разных языках, проект не будет компилироваться. Для того, чтобы использовать два языка, необходимо создать поддиректорию, добавить ее в файле web.config и поместить в нее файлы на другом языке.

Регистрация в файле web.config:

<configuration>
  <system.web>
    ...
    <compilation>
      <codeSubDirectories>
        <add directoryName="VBCode"/>
      </codeSubDirectories>
      <codeSubDirectories>
        <add directoryName="CSCode"/>
      </codeSubDirectories>
    </compilation>
    ...
  </system.web>
</configuration>

Директивы

На каждой странице aspx обычно задаются директивы, с помощью которых Вы можете контролировать поведение страницы. Можно считать их языком, с которым вы общаетесь с компилятором, указывая ему, как обрабатывать данную страницу. Директивы обычно помещают в начале файла. Мы уже встречались с директивой Page в первой лекции.

Синтаскис объявления директив такой:

<%@ [Directive] [Attribute=Value] %>

Можно объявить несколько директив одновременно:

<%@ [Directive] [Attribute=Value] [Attribute=Value] %>

В ASP.NET 2.0 существует 11 директив.
Директива Атрибуты Описание
@Assembly Name
Src Импортирует на страницу или в элемент управления сборку с заданным именем
@Control такие же, как у Page Применяется для задания свойств при создании собственных пользовательских элементов управления.
@Implements Interface Указывает, что класс данной страницы реализует данный интерфейс
@Import Namespace Импортирует пространство имен
@Master такие же, как у Page Применяется на страницах шаблона дизайна(Master page). Новая в ASP.NET 2.0
@MasterType TypeName
VirtualPath Дает строго типизированную ссылку на класс, содержащийся в шаблоне дизайна. Позволяет обращаться к свойствам этого класса.
@OutputCache Duration
Location
VaryByCustom
VaryByHeader
VaryByParam
VaryByControl Управляет кэшированием страницы или элемента управления. Подробнее описана в лекции 15.
@Page см. Ниже Атрибуты, относящиеся к данной странице. Употребляется только в файлах с расширением aspx
@PreviousPageType TypeName
VirtualPath Страница, с которой были отправлены данные, введенные пользователем. Новая в ASP.NET 2.0. Раньше страницы отправляли пост только самим себе.
@Reference Page
Control Страница или элемент управления, который нужно компилировать вместе с данной
@Register Assembly
Namespace
Src
TagName
TagPrefix Создает псевдонимы для пространств имен и пользовательских элементов управления

Пока что подробно рассмотрим 2 из них – Page и Import.

Директива Page

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

Наиболее важные атрибуты директивы перечислены в таблице:
AutoEventWireup Автоматическая обработка событий страницы
Buffer Управляет буферизацией страницы. По умолчанию буферизуется
ClassName Позволяет назначать имя класса, сгенерированного данной страницей
CodeFile Название файла с отделенным кодом для данной страницы
Culture Устанавливает набор региональных параметров, т.е. язык, формат валюты, даты, чисел
Debug Если true, на страницу выводится отладочная информация
Trace Вывод трассировочной информации
EnableViewState Сохранение состояния страницы. По умолчанию она сохраняется
EnableTheming Позволяет включить или выключить поддержку тем оформления. По умолчанию включено
Inherits Класс, от которого наследуется класс данной страницы в технологии отделенного кода
IsAsync Показывает, обрабатывается ли страница асинхронно.
Language Язык, используемый во внедренном коде
WarningLevel Наибольший допустимый уровень предупреждений компилятора
CompilerOptions Опции компилятора

Пространства имен библиотеки классов

Библиотека классов FCL содержит тысячи классов. Для удобства использования они объединены в пространства имен. Чтобы обращаться к классам, объявленным в пространстве имен, без указания полного пути, его нужно импортировать в проект. Если вы хотите работать с файлами формата XML, вам нужно импортировать пространство имен System.XML. В страницах отделенного кода на C#, как всегда, используется директива using.

using System. XML;

На странице aspx – директива Import

<%@ Import Namespace= "System.XML " %>

Для каждого пространства имен требуется отдельная директива Import.

Visual Studio.NET и VWD по умолчанию включают в страницу на C# наиболее часто используемые пространства имен. На страницу aspx импортировать эти пространства имен не требуется.

using System;
  using System.Data;
  using System.Configuration;
  using System.Collections;
  using System.Web;
  using System.Web.Security;
  using System.Web.UI;
  using System.Web.UI.WebControls;
  using System.Web.UI.WebControls.WebParts;
  using System.Web.UI.HtmlControls;

Например, в пространстве имен System.Web.UI находится класс Page, без которого не может существовать ни одна страница ASP.NET, в System.Web - HttpRequest и HttpResponse.

Программа просмотра классов

Как же узнать, какие классы имеются в библиотеке классов .NET? Для этого предназначен Object Browser (Visual Studio 2005) и Class Browser WebMatrix. Чтобы открыть Object Browser в Visual Studio 2005 или VWD Express, выберите пункт меню View-> Object Browser. Если вы используете WebMatrix, то Class Browser находится в той же папке меню Windows, что и WebMatrix – All Programs->ASP.NET WebMatrix. В формате ASP.NET Class Browser включен в состав Framework SDK.

Все имеющиеся пространства имен показаны как узлы древовидной структуры. Нас интересует System.Web. Раскройте этот узел. Внутри оказались другие пространства имен. Раскройте System.Web.UI. Там находится большое количество классов, интерфейсов, делегатов, перечислений. Их можно узнать по иконкам. Например, иконка делегата похожа на чемодан.

- класс

- интерфейс

- событие

- перечисление

- метод

Выберите класс Page. В окошке справа появится список его методов, полей и событий. Если выбрать метод, в третьем окне под вторым появится его описание. Внутри класса находятся еще две папки – классов-прародителей(Base Classes) и классов-потомков. Все их тоже можно просмотреть. Object Browser показывает и классы текущего проекта. Если классы закомментирован тегами генерации документации XML, то эта информация тоже видна, например Summary, Parameters, Values, Returns.

Исследуя свойство IsPostBack, можно узнать, что оно имеет булевское значение, и предназначено только для чтения.

Проверка соответствия стандартам

Существуют разные стандарты HTML и XHTML. Более поздние стандарты предъявляют более строгие требования, например, XHTML 1.1 не разрешает пользоваться <br> и другими простыми тегами без закрывающего слэша <br/>. В то же время старые стандарты не поддерживают новые теги.

В заголовке HTTP-запроса указывается стандарт документа, Visual Studio 2005 во всех страницах указывает следующий стандарт:

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

Этот стандарт требует наличия атрибута xmlns в теге <html> - ссылки на сайт с описанием стандарта.

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

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

Страница – это основа всего в Web-приложении.

Класс System.Web.UI.Page инкапсулирует функциональность, необходимую для создания и обработки страниц ASP.NET.

Каждая страница ASP.NET – это объект класса, который автоматически генерируется ядром ASP.NET. Класс наследуется от ассоциированного со страницей класса, если мы используем отделенный код, или прямо наследуется от System.Web.UI.Page, если код на C# встроен в страницу. Среда также создает конструктор по умолчанию.

Чтобы убедиться в этом, можем создать страницу “PageType.aspx”:

<%@ Page Language="C#" %>
  <html xmlns="http://www.w3.org/1999/xhtml" >
  <head runat="server">
      <title>Тип страницы</title>
  </head>
  <body>
      <div>
      <% Response.Output.Write("Тип данной страницы {0}",this.GetType()); %>
      </div>
       <div>
      <% Response.Output.Write("Базовый тип данной страницы {0}",this.GetType().BaseType); %>
      </div>
  </body>
  </html>

Вот результат:

Тип данной страницы ASP.pagetype_aspx
Базовый тип данной страницы System.Web.UI.Page

Такая же страница, созданная по технологии разделения кода.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="PageType.aspx.cs" Inherits="PageType" %>

пишет результат

Тип данной страницы ASP.pagetype_aspx
Базовый тип данной страницы PageType

То, что PageType – наследник System.Web.UI.Page, прописано в файле отделенного кода:

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

К текущему объекту страницы можно обращаться как к переменной Page. Page – это контейнер элементов управления данной страницы, поэтому содержит в себе коллекцию Controls. Если в теге <head> присутствует атрибут runat = “server”, то в Page содержится и поле Header, через которое можно управлять заголовком страницы. Например, поменять название странице в заголовке браузера, назначить файл каскадных таблиц стилей.

<script runat="server">
      protected void Page_Init(object sender, EventArgs e)
      {     
          HtmlLink myHtmlLink = new HtmlLink();
          myHtmlLink.Href = "printable.css";
          myHtmlLink.Attributes.Add("rel", "stylesheet");
          myHtmlLink.Attributes.Add("type", "text/css");
          Page.Header.Controls.Add(myHtmlLink);
          Page.Header.Title = "Новый заголовок";
     }
      protected void Page_Load(object sender, System.EventArgs e)
      {
          Style bodyStyle = new Style();
          bodyStyle.ForeColor = System.Drawing.Color.Blue;
          bodyStyle.BackColor = System.Drawing.Color.Beige;
          Page.Header.StyleSheet.CreateStyleRule(bodyStyle, null, "p");
      }
  </script>
  <html xmlns="http://www.w3.org/1999/xhtml" >
  <head runat="server">
      <title>Hello ASP.NET</title>
  </head>
  <body>
        <p>Учитесь программировать на ASP.NET</p>
  </body>
  </html>

В этом примере мы поменяли текст заголовка. Запустите эту страницу. В получившемся HTML-коде внутри тега <title> стоит уже не «Untitled Page», а «Новый заголовок», который был установлен через Page.Header.Title. Был создан стиль для тега <p>, что отразилось таким образом:

<style type="text/css">
        p { color:Blue;background-color:Beige; }
  </style>

Внешняя страница CSS была импортирована из файла.

<link href="printable.css" rel="stylesheet" type="text/css" /><style type="text/css">

Если атрибут AutoEventWireup, который присутствует в заголовке страниц, генерируемых VS, установлен, то методы с префиксом Page_ автоматической назначаются обработчиками событий страницы.

У страницы есть два важных свойства - Response и Request. Свойство Response имеет тип HttpResponse. Response страницы можно воспринимать как выходной поток. Весь HTML код генерируемой страницы в принципе может быть выведен через запись в этот поток. Это был обычный способ работы разработчиков asp. Но в ASP.NET есть более удобные средства вывода данных с помощью серверных элементов управления. Response лучше использовать для записи Cookies, для задания различных параметров заголовка – управлять кэшированием, свойством Expires.

Вот пример из MSDN:

HttpCookie MyCookie = new HttpCookie("LastVisit");
      DateTime now = DateTime.Now;
      MyCookie.Value = now.ToString();
      MyCookie.Expires = now.AddHours(1);
      Response.Cookies.Add(MyCookie);

Можно поменять кодовую страницу.

<head runat="server">
  <%Response.Charset = "windows-1251"; %>
      <title>Русская кодировка</title>
  </head>

Функция Response.Redirect перенаправляет браузер на другую страницу.

Response.Redirect("NavigationTarget.aspx?name=" + System.Web.HttpUtility.UrlEncode(Name.Text);

Здесь формируется командная строка с параметрами QueryString, которые целевая страница может прочитать.

Аналогично свойство Request – это запрос, переданный на сервер для вывода нужной страницы. Он имеет тип HttpRequest. В нем хранится все о клиенте, включая настройки его браузера, файлы-cookie и данные, введенные им в форму.

NameLabel.Text = Server.HtmlEncode(Request.QueryString["Name"]);

События страницы

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

Затем начинается жизненный цикл страницы. Он начинается с этапа PreInit. После получения запроса среда выполнения загружает класс вызываемой страницы, устанавливает свойства класса страницы, выстраивает дерево элементов, заполняет свойства Request и Response и свойства UICulture и вызывает метод IHttpHandler.ProcessRequest. После этого среда выполнения проверяет, каким образом была вызвана эта страница, и если страница вызвана путем передачи данных с другой страницы, о чем будет рассказано далее, то среда выполнения устанавливает свойство PreviousPage.

На этом этапе устанавливается также свойство IsPostback объекта Page, которое позволяет узнать, в первый ли раз загружается форма или она должна формироваться как результат обработки данных, введенных пользователем.

В обработчиках событий страницы можно проверить это свойство:

if (!Page.IsPostBack)
      {
          // обрабатывать
      }

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

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

Если на странице существуют валидаторы(классы проверки данных, см. лекцию 5), то для них вызывается метод Validate(). Затем вызыва