Конфигурация компонентов с помощью XML-файлов
Декларативный подход к программированию
Возможность отладки и обработки ошибок
Компилируемость кода и модульность объектов
Система доступа к базам данных
Объект DataGrid — расширение возможностей!
В первых статьях серии «ASP на блюдечке» мы ознакомились с ASP и рассмотрели все основные тонкости построения разнообразнейших Web-интерфейсов. Настала пора ознакомить читателей с обновленным ASP — ASP+.
Итак, настоящая статья предназначена для тех, кто хотел бы ознакомиться с ASP+ и попробовать создать собственную универсальную Web-систему доступа к базам данных с его помощью.
ASP+ не просто очередная версия активных серверных страниц (Active Server Pages (ASP)), а унифицированная платформа для Web-разработки, обеспечивающая разработчиков всеми средствами, необходимыми для реализации Web-приложений корпоративного уровня. ASP+ — неотъемлемая составляющая этого нового решения от Microsoft, получившего название NGWS. Аббревиатура достаточно загадочна и носит весьма условный характер. Объясняется это тем, что Microsoft пока выпустила лишь первую бета-версию Visual Studio.NET (Beta 1), которая, по замыслу ее создателей, предназначена для знакомства разработчиков с новой технологией создания Web-приложений. Однако не следует забывать о том, что почти половина вложений Microsoft в развитие новых технологий в настоящее время приходится именно на долю группы разработки .NET, откуда явствует, что в недалеком будущем последует целый ряд продуктов этой серии.
И хотя специалисты Microsoft весьма настоятельно рекомендуют пока воздержаться от разработок с использованием .NET Framework SDK Beta 1, мы попробуем взглянуть на эту новую технологию программирования Web-приложений и попытаемся оценить ее с точки зрения разработчика.
В некоторых источниках NGWS расшифровывается как Next Generation Web Studio — Web-студия следующего поколения — по сути среда, в которой разработчики могут писать код на любом совместимом языке программирования, таком как Visual Basic, Managed Extensions for C++, C# (произносится как Си-Шарп) или JScript. Главной новостью является то, что, по сути, вся платформа NGWS во время выполнения приложения доступна для последнего. Кроме того, код компилируется. Разработчикам доступны такие механизмы, как управление во время работы (at runtime), «безопасность» синтаксического набора, наследование, инкапсуляция и полиморфизм.
ASP+ изначально задумывался и был разработан для интеграции с HTML-редакторами и со средствами разработки, выполненными в соответствии со спецификацией WYSIWYG, в частности с Microsoft Visual Studio 7.0. Это позволило обогатить средства, предоставляемые уже знакомым нам программным обеспечением, новыми возможностями, к примеру, разработкой оконного Web-интерфейса.
У читателей может возникнуть подозрение, что ASP+ попросту является очередной версией ASP, с некоторыми изменениями, дополнениями и т.д. Не стоит заблуждаться. ASP — это всего лишь надстройка над операционной системой, выполненная в виде динамически загружаемой библиотеки прикладного интерфейса ISAPI. ASP+ — многофункциональный модульный набор компонентов. Хотя в ASP+ все-таки предусмотрена некоторая синтаксическая совместимость с ASP, модель, в отличие от ASP, здесь куда более обширна, а измененная инфраструктура позволяет разрабатывать принципиально новые Web-приложения.
Давайте ознакомимся с основными преимуществами ASP+ перед ASP.
В ASP+ по сравнению с ASP сильно расширены возможности по хранению переменных состояния страниц. Для этого здесь используются серверные элементы управления, что позволяет разработчику сохранять значения переменных формы, когда пользователь перемещается от одной страницы к другой, не загромождая каждую страницу вызовами огромного количества функций для считывания состояний всех «предыдущих» страниц. Кроме того, ASP+ поддерживает скрытые переменные формы «на клиенте», что заметно
В ASP+ реализован ряд серверных элементов управления, которые незаменимы при создании сложных HTML-документов. Элементы поддерживают код, управляющий их поведением во время выполнения. Эти серверные управляющие элементы — календарь, списки, специальные компоненты для работы с базами данных (так называемые Data-Aware Controls), таблицы и т.п., — включенные в .NET, дают представление о том, насколько расширятся возможности разработчиков при создании Web-страниц.
В ASP+ сделана явная попытка заинтриговать разработчиков, для которых более привычным языком программирования является C++. Для тех, кому C++ знаком, не нужно объяснять, почему он на сегодняшний день является самым гибким универсальным языком программирования. Языки описания сценариев, на которых пишутся активные серверные страницы (VBScript и JavaScript), далеко не самое удобное средство для разработчиков, особенно для тех, кому привычнее и удобнее «излагать свои мысли» на C++. Конечно, разработчик свободен в выборе языка описания. Но это еще не самое важное. В ASP+ окончательно достигнута возможность четкого разграничения кода и Web-форм (Web-страниц), что позволяет разработчикам с одинаковым успехом создавать и поддерживать как небольшие, так и очень крупные Web-проекты. Код инкапсулирован в серверных элементах управления, а новая методика обработки событий наконец-то дает возможность создавать страницы с разумной архитектурой.
Компоненты ASP+ используют конфигурационные файлы XML. Это означает, что необходимость их регистрации на сервере с остановкой и перезапуском IIS отпадает, что несомненно «облегчит жизнь» тем Web-разработчикам, кто реализует «чужие» Web-приложения и кому администрирование IIS недоступно. Для развертывания Web-приложений достаточно скопировать файлы на сервер.
Наверняка большинство разработчиков со мной согласится, что декларативный подход имеет бесспорные преимущества по сравнению с функциональным. Это преимущество особенно заметно, если вы пользуетесь каким-либо визуальным ASP+-редактором, к примеру Visual Studio.NET. С помощью VS.NET вы можете «перетащить» небольшую иконку с изображением ASP+-компонента на Web-форму и задать необходимые этому компоненту свойства. Все остальное объектная модель ASP+ возьмет на себя. В качестве примера давайте сравним два фрагмента одного и того же кода, написанного на ASP:
<input type="text" name="firstname" value="<%= request("firstname") %">
и на ASP+:
<asp:Textbox id="firstname" maintainstate="true" runat="server" />
Согласитесь, что преимущество второго примера кода перед первым очевидно, поскольку во втором случае отсутствуют указания на выполнение каких бы то ни было действий, чего нельзя сказать о первом случае.
Отладка ASP-приложений всегда оставалась понятием весьма абстрактным. И на самом деле, о какой отладке может идти речь, когда зачастую самым информативным средством о допущенных на странице ошибках является старый добрый процессор Internet Explorer’а. В ASP+ же реализованы средства обработки ошибок, отладки и трассировки, позволяющие интегрально отлаживать Web-приложение вне зависимости от языков разработки отдельных модулей и компонентов. С NGWS SDK поставляется NGWS SDK Debugger, поддерживающий локальную отладку Web-приложений (Web-приложений на локальном сервере). Однако Microsoft обещает включить в комплект поставки Visual Studio 7.0 так называемый Visual Studio Debugger, который будет способен отлаживать в том числе и ASP+-код как на локальном, так и на удаленном сервере с возможностью автоматического подсоединения во время выполнения и редактирования кода непосредственно в процессе отладки создаваемого Web-приложения.
Средства защиты в ASP ограниченны. Ведь, по сути, аутентификация пользователя на странице может быть выполнена не иначе как с использованием средств аутентификации браузера. Эта вынужденная «заточка под браузер», с одной стороны, создает для разработчиков ряд неудобств, с другой — открывает ряд брешей. В ASP+ администраторам IIS и разработчикам доступны новые возможности аутентификации пользователей, где обычные HTML-формы преобразуются в специализированные страницы для регистрации.
ASP+ намного превосходит ASP по производительности за счет поддержки кэширования на стороне севера, что позволяет сохранять и повторно использовать в страницах данные любого типа. Кроме того, ASP+ может кэшировать и представление страниц ASP+ на стороне клиента, что обусловливает повышение производительности.
Для повышения производительности ASP+ использует не только преимущества, введенные архитектурой среды NGWS. Еще одним фактором, благоприятно влияющим на увеличение производительности, является компилируемость. В ASP серверные страницы интерпретировались непосредственно перед загрузкой их клиентом, а в ASP+ они компилируются (технология так называемой JIT (Just In Time)-компиляции). Кроме того, ASP+ позволяет моделировать создаваемое приложение в зависимости от совокупности используемых объектов. Так, к примеру, можно отказаться от загрузки модуля объекта, если он не является необходимым при разработке Web-приложения.
В распоряжении разработчиков ASP+-приложений имеются три программные модели, которые он волен использовать как по отдельности, так и совместно:
Итак, специалисты Microsoft полностью переписали ASP и избавились от присущих этой среде ограничений. ASP+ сочетает в себе мощь, достаточную для разработки сложных Web-приложений, с простотой, позволяющей создавать их за разумное время.
Давайте продолжим наше знакомство с ASP+ на примере: рассмотрим универсальную
систему доступа к базам данных с возможностью выполнения запросов и получения
результатов как в виде таблицы, так и в форме XML-файла. Не правда ли, полезная
штука. Для ее написания будем использовать ASP+, ADO+ и C#. Для компиляции и
выполнения приложения нам потребуется .NET Framework SDK, который лежит здесь
.
Первое, что нам понадобится, это установить .NET Framework SDK, который, в свою очередь, требует наличия MSIE 5.5 и MSDAC 2.6.
Далее следует прописать MIME для файлов с расширением .aspx, для чего необходимо:

Теперь, когда наш IIS «научился» понимать файлы с расширением .aspx — то есть ASP+, можно приступать к созданию основной формы, посредством которой и будет реализован интерфейс к базам.
Настоятельно рекомендую не смешивать HTML-представления с кодом в одном файле по двум причинам:
Кроме того, следует уяснить себе еще один момент. Концепция JIT-компиляции ASP+-приложений заключается в том, что ASP+ сам отслеживает изменения, вносимые в исходные файлы, и в зависимости от этого перекомпилирует результат. Здесь очевидны немалая временная задержка при первом запуске и реальная прибавка производительности при последующих запусках.
Система доступа к базам данных, по сути, представляет собой Web-версию популярной программы ISQL, входящей в состав Microsoft SQL-сервера, а фактически позволяет подключаться и выполнять запросы к удаленному или локальному SQL-серверу. При этом указываются сервер, база данных, учетная запись (login) и пароль доступа. Исходя из введенных значений система пытается осуществить подключение и выполнить введенный запрос. Результат по желанию может быть сформирован или в табличном, или в XML-представлении.
Итак, приступим к созданию нашего Web-интерфейса. Для начала изготовим форму диалога с пользователем:
<%@Page Language="C#" Inherits="Aquarius. AquariusWI " Src="WebSql.cs" Trace="False" %>
Для читателей почти все должно быть очевидным. Во-первых, первая директива указывает на то, что в качестве языка описания сценариев используется язык C#. Во-вторых, создаваемая форма будет наследовать свойства и методы класса Aquarius, описанного в исходном файле «WebSql.cs». В-третьих, директива Trace=«False» указывает на то, что в настоящий момент режим отладки приложения выключен и ASP+ не будет выдавать в качестве результата работы страницы подробный отчет обо всех последовательно произведенных действиях и событиях.
Однако возможен и следующий вариант:
<%@Page Language="C#" Inherits="Aquarius. AquariusWI " Codebehind=" WebSql.dll"" Trace="False" %>
В данном случае ссылка «исходный файл» заменена ссылкой на результат его компиляции. По умолчанию система будет производить поиск последнего в подкаталоге bin корневого каталога нашего Web-приложения. Разумеется, заранее необходимо позаботиться о наличии этого файла именно там, прекомпилировав его с помощью процедуры nmake.exe (для того чтобы узнать, как это сделать, достаточно запустить ее без параметров). Такая технология позволит скрыть исходные тексты ваших приложений даже от лиц, имеющих доступ к серверным файлам.
Далее страница-интерфейс мало чем отличается от обычной HTML-страницы, разве что несколькими типичными для ASP+ компонентами. Давайте рассмотрим их подробнее:
<asp:TextBox id="txtServer" size=20 maxLength=20 runat="server"/>
Таким способом можно создать текстовое поле размером и числом максимально вводимых символов, равными 20, с названием «txtServer». Давайте разберемся с последней директивой: Runat= «server». Этот атрибут указывает компилятору на то, что к данному элементу будет осуществлен программный доступ, то есть данный объект интерфейса может быть обработан программно. Однако необходимость в этом возникает далеко не всегда, и именно поэтому следует прибавлять данную директиву не ко всем компонентам интерфейса страницы, а лишь применительно к тем, обработка событий которых нам потребуется в дальнейшем.
Так, по сути, компонент <asp:TextBox> представляет собой ASP+ вариант обычного HTML -компонента <input type="text">. Аналогом же компонента <select> является компонент
<asp:DropDownList id=lstDatabases size=1 AutoPostBack="True" OnSelectedIndexChanged="lstDatabases_Change" MaintainState="True" runat="server" />
Директива AutoPostBack= «True» указывает компилятору ASP+-страницы создать клиентский механизм отсылки страницы обратно на сервер при возникновении события, требующего программной обработки. К примеру, в вышеприведенном случае компилятор автоматически вернет серверу страницу при возникновении события OnChange и вызовет его обработчик lstDatabases_Change.
Необходимый для возврата код будет сгенерирован компилятором автоматически. В данном случае будет сгенерирован следующий код:
<select name="lstDatabases" id="lstDatabases" size="1" onchange="javascript:__doPostBack('lstDatabases', '')">
где __doPostBack функция вида:
function __doPostBack (eventTarget, eventArgument)
Как видите, __doPostBack() — это JavaScript-код, выполняющийся на стороне клиента и попросту извлекающий идентификатор обрабатываемого компонента интерфейса и необходимую дополнительную информацию (аргументы), которую он посылает обратно на сервер, где она обрабатывается соответствующим обработчиком. С точки зрения управления результирующая HTML-страница в браузере выглядит следующим образом:
<script language="javascript">
function __doPostBack(eventTarget, eventArgument)
{
var theform = document.ctrl1
theform.__EVENTTARGET.value = eventTarget
theform.__EVENTARGUMENT.value = eventArgument
theform.submit()
}
</script>
…
<select name="lstDatabases" id="lstDatabases" size="1" onchange="javascript: __doPostBack('lstDatabases', '')">
…
<input type="checkbox" id="chkSavePassword" value="chkSavePassword" name="chkSavePassword">
…
<select name="lstSave" id="lstSave" onchange="javascript:__doPostBack('lstSave', '')">
…
Давайте посмотрим, как выглядит вышеупомянутый обработчик события OnChange:
protected void lstDatabases_Change (object sender, EventArgs e)
{
if (lstDatabases.Items[lstDatabases.SelectedIndex].Value == TEXT_REFRESH) {
string sql_conn_str = "server=" + _ServerName + ";uid=" + _UserName + ";password=" + _Password + ";database=Master";
SQLConnection myConnection = new SQLConnection (sql_conn_str);
SQLDataSetCommand myCommand = new SQLDataSetCommand(COMMAND_DATABASES, myConnection);
try
{
DataSet ds = new DataSet();
myCommand.FillDataSet(ds,"Databases");
lstDatabases.DataTextField = "Name";
lstDatabases.DataValueField = "Name";
lstDatabases.DataSource = ds.Tables["Databases"].DefaultView; lstDatabases.DataBind();
}
catch (Exception eo)
{
HandleException(eo);
}
finally
{
if (myConnection.State == DBObjectState.Open)
myConnection.Close();
}
}
}
Обработчик события OnChange компонента lstDatabases (lstDatabases_Change) проверяет выбранное значение в выпадающем списке выбора на предмет его совпадения с константой TEXT_REFRESH. Если выбранное значение не совпадает с константой, то метод завершает свою работу. В противном случае (когда известно, что пользователь пытается обновить базу данных) строится строка соединения с базой данных исходя из введенных пользователем значений:
string sql_conn_str = "server=" + _ServerName + ";uid=" + _UserName + _ ";password=" + _Password + ";database=Master";
Переменные _ServerName, _UserName, и _Password являются переменными членами класса AquariusWI, определяемыми в классе в ходе выполнения процедуры загрузки страницы и принимающими значения, введенные пользователем в компонентах txtServer, txtUser и txtPassword соответственно:
public class AquariusWI : Page
{
private string _DatabaseName;
private string _ServerName;
private string _UserName;
private string _Password;
protected void Page_Load (object sender, EventArgs e)
{
...
_ServerName = txtServer.Text;
_UserName = txtUser.Text;
_Password = txtPassword.Text;
...
}
...
}
Теперь, когда у нас уже есть строка подключения, нам необходимо создать экземпляр объекта типа SQLConnection (соединения с базой данных) следующим образом:
SQLConnection myConnection = new SQLConnection (sql_conn_str);
Далее следует создать экземпляр ADO+ объекта типа SQLDataSetCommand, который является аналогом объекта Command ADO. Для этого воспользуемся константой
COMMAND_DATABASES. SQLDataSetCommand myCommand = new SQLDataSetCommand(COMMAND_DATABASES, myConnection);
После этого необходимо создать ADO+-объект доступа к данным — DataSet. Из предыдущей статьи известно, что объект DataSet — это представление в памяти, содержащее наборы таблиц, их отношений и связей. Объект DataTable является аналогом ADO-объекта RecordSet и служит для выполнения операций над наборами данных.
Объект DataTable состоит из единственной таблицы, которая может представлять собой результат выполнения определенной выборки, хранимой процедуры, вида и т.д. Иначе говоря, объект DataTable содержит данные, а объект DataSet содержит объект(ы) DataTable.
Далее следует блок try — catch — finally, служащий для обработки исключений. Здесь важно отметить, что метод FillDataSet объекта SQLCommand заполняет объект DataSet в зависимости от команды, заданной в SQLDataSetCommand. Второй параметр — «Databases», по сути, позволит нам обозначить результаты работы запроса определенным именем, используя которое можно будет в дальнейшем ссылаться на данные из результата этого запроса.
Далее необходимо осуществить две привязки данных в только что полученной таблице «Databases» типа DataTable с выпадающим списком выбора lstDatabases типа <asp: DropDownList>: привязку текста, показываемого пользователю с полем «Name» нашего объекта типа DataTable при помощи метода DataTextField, и привязку значения каждого пункта выпадающего списка выбора с помощью метода DataValueField.
Установка свойства DataSource нашего выпадающего списка выбора (lstDatabases) позволяет окончательно задать таблицу для связывания со списком выбора:
lstDatabases.DataSource = ds.Tables["Databases"].DefaultView;
После этого достаточно будет одного вызова метода DataBind(), который свяжет все объекты нашей страницы, для которых заданы параметры связей:
lstDatabases.DataBind();
В случае возникновения ошибки можно попросту выставить свойство «text» объекта типа Label (метка) — <asp:Label id="lblMessage"> равным значению текста, соответствующего коду возникшей ошибки:
Catch (Exception eo)
{
lblMessage.Text = e.Message.ToString();
}
После выполнения всех действий необходимо проверить и закрыть соединение с базой данных, если оно открыто:
finally
{
if(myConnection.State == DBObjectState.Open)
myConnection.Close();
}
Теперь стоит разобраться с функцией загрузки страницы Page_Load, которая, заметьте, вызывается после вызова любого конструктора компонентов класса:
protected void Page_Load (object sender, EventArgs e)
{
if ( lstDatabases.SelectedIndex != -1 )
_DatabaseName = lstDatabases.Items [lstDatabases.SelectedIndex]. Value;
_ServerName = txtServer.Text;
_UserName = txtUser.Text;
_Password = txtPassword.Text;
if (!Page.IsPostBack) {
BordersOn.Checked = true;
rdoHTML.Checked = true;
ListItem item = new ListItem (TEXT_BLANK, "");
lstSave.Items.Add (item);
lstDatabases.Items.Add ("");
lstDatabases.Items.Add (TEXT_REFRESH);
}
if ( ! chkSavePassword.Checked) {
txtPassword.Text = "";
}
}
Помимо оговоренных инициализаций переменных _ServerName, _UserName, и _Password здесь с самого начала выполняется инициализация переменной _DatabaseName, причем делается это только в том случае, если из соответствующего выпадающего списка выбора выбрано значение, то есть когда индекс выбранного значения из списка не равен -1.
Далее необходимо выяснить, является ли данная загрузка страницы первой, с тем чтобы выполнить ряд действий по инициализации компонентов нашего Web-интерфейса. Для этого лучше всего воспользоваться переменной — членом класса Page (объекта страница) IsPostBack, которая принимает значение «False», если страница загружается в первый раз и «True», если нет.
Если загрузка страницы является первой, то необходимо выставить значения «радиокнопок» BordersOn и HTML, подготовить и добавить пункт в список выбора только что выполненных запросов lstSave. Константа TEXT_BLANK служит для отображения в списке выбора, а константа "" соответствует ее значению. И наконец, необходимо проверить значение флажка запоминания пароля и обнулить поле «пароль», в случае если флажок сброшен:
txtPassword.Text = "";
Теперь разберемся с другими обработчиками событий, возникающих при действиях пользователей. Для начала рассмотрим обработчик нажатия на кнопку «Save Query», посредством которой пользователь может сохранить введенные ранее запросы и добавить их в выпадающий список выбора lstSave:
protected void btnSave_Click (object sender, EventArgs e)
{
String QueryValue = txtQuery.Text;
int length = QUERY_LIST_MAX;
if (QueryValue.Length < QUERY_LIST_MAX)
length = QueryValue.Length;
ListItem item = new ListItem (QueryValue.Substring(0,length), QueryValue);
lstSave.Items.Add (item);
}
По сути, этот компонент интерфейса должен сохранять содержимое компонента, в который вводится текст запроса всякий раз, когда пользователь потребует этого. Для начала присвоим это значение внутренней переменной QueryValue. Далее создадим локальную переменную Length и присвоим ей значение константы QUERY_LIST_MAX, которая содержит значение максимально допустимой строки запроса, показываемой в списке выбора lstSave. Если длина строки меньше константы, то необходимо сосчитать длину первой.
И наконец, необходимо добавить в список запросов строку и ее значение. Для этого, во-первых, необходимо извлечь из исходной строки ровно length символов. Воспользуемся функцией SubString, с помощью которой укажем, что строку необходимо извлечь начиная с позиции 0 и длиной в length символов от исходной:
QueryValue.Substring(0,length)
Таким образом, мы используем «обрезанную» строку для ее показа в списке и исходную, — для хранения ее в качестве значения.
Далее создадим и добавим новый элемент к списку выбора:
ListItem item = new ListItem(QueryValue.Substring(0,length), QueryValue); lstSave.Items.Add(item);
Теперь настала пора разобраться и с обработчиком нажатия на кнопку выполнения запроса — «Execute Query»:
protected void btnExecute_Click(object sender, EventArgs e)
{
string sql_conn_str = "server=" + _ServerName + ";uid=" + _UserName + ";password=" + _Password + ";database=" + _DatabaseName;
string sql_command = txtQuery.Text;
SQLConnection myConnection = new SQLConnection(sql_conn_str);
SQLDataSetCommand myCommand = new SQLDataSetCommand(sql_command, myConnection);
DataSet ds = new DataSet();
Try
{
myCommand.FillDataSet(ds,"Query");
switch (rdoXML.Checked)
{
case true: txtXML.Visible = true;
txtXML.Text = ds.Xml;
break;
case false: grdResults.BorderWidth = BordersOn.Checked.ToInt32();
grdResults.DataSource = ds.Tables["Query"].DefaultView;
grdResults.DataBind();
break;
}
}
catch (Exception eo)
{
HandleException (eo);
}
finally
{
if (myConnection.State == DBObjectState.Open)
myConnection.Close();
}
btnClearResults.Visible = true;
}
Здесь, как и в обработчике Change объекта lstDatabases, строится строка подключения к базе данных — sql_conn_str и также создается объект SQLDataSetCommand. Обратите внимание, что в качестве переменной текста SQL-запроса используется текст, введенный пользователем и хранящийся в переменной sql_command. Таким образом, метод SQLDataSetCommand выполнит любой запрос, находящийся в переменной sql_command, а следовательно, введенный пользователем в соответствующее текстовое поле (поле Text компонента txtQuery).
Далее попробуем выполнить метод FillDataSet только что созданного экземпляра объекта SQLDataSetCommand — myCommand и проверим значение флажка показа результатов выполнения запроса в виде таблицы (или в виде XML).
Если пользователь выбрал режим просмотра результатов в виде XML, выставим флажок видимости (Visible) соответствующего текстового поля (txtXML <asp:TextBox>) в true. После этого от нас потребуется попросту установить свойство XML заполненного объекта DataSet (ds) равным значению поля Text текстового поля txtXML <asp:TextBox>.
Если же пользователь выбрал режим просмотра результатов в виде таблицы, присвоим переменной ширины разделительных линий таблицы BorderWidth объекта типа DataList (переменная grdResults) значение, равное целочисленному значению логической переменной Checked радиокнопки-переключателя включения/выключения показа разграничительных линий BordersOn. Вот и все, осталось только насладиться простотой и гибкостью связывания данных с помощью ASP+ и ADO+, выставив значение свойства DataSource объекта типа DataList равным значению по умолчанию (DefaultView). После этого можно вызывать метод DataBind и любоваться результатом.

Результат в виде таблицы

Результат в виде XML
Рассмотренная система состоит всего из двух файлов: WebSql.aspx — страницы с представлением интерфейса и WebSql.cs — описания класса AquariusWI с обработчиками событий и методами работы приложения. Архив исходных текстов Web-приложения лежит здесь.
В заключение хотелось бы привести еще один пример, ярко иллюстрирующий преимущества ASP+ перед ASP. Для этого давайте рассмотрим, пожалуй, наиболее простую задачу, которую тем не менее наверняка приходится решать каждому Web-программисту чаще других: отображение содержимого таблицы базы данных в виде HTML-таблицы. Задача довольно простая и, в принципе, легко осуществимая с помощью ASP. Давайте оценим, насколько облегчается ее решение и насколько расширяются возможности при использовании ASP+ — компонента DataGrid. Начнем с элементарного — формирования данных в виде обычной таблицы:
<%@ language="vb" %>
<%@ import namespace="system.data" %>
<%@ import namespace="system.data.ado" %>
<script language="vb" runat="server">
dim cnn as adoconnection
dim cmd as adodatasetcommand
dim ds as new dataset
public sub page_load(sender as object,e as eventargs)
if page.ispostback=false then
cnn=new adoconnection("dsn=sample")
cmd=new adodatasetcommand("select * from authors",cnn)
cmd.filldataset(ds,"authors")
grid1.datasource=ds.tables("authors").defaultview
grid1.databind()
end if
end sub
</script>
<form id=form1 runat="server">
<asp:datagrid id="grid1" runat="server" />
</form>
Как видите, осуществляется элементарная привязка объекта типа DataGrid с источником данных. В данном случае для этого используется ODBC алиас sample, база данных Pubs и таблица Authors.
Попытаемся теперь добиться от этого компонента большей управляемости. Оставим первоначальный код без изменений, но добавим несколько штрихов к нашей таблице. Изменим лишь объявление компонента таким образом, чтобы заголовок полученной таблицы был синего цвета, а строки поочередно светло- и темно-серого.
<asp:datagrid id="grid1" runat="server" headerstyle-backcolor="blue" headerstyle-forecolor="white" alternatingitemstyle-backcolor="gray" itemstyle-backcolor="silver"/>
Отображение таблиц или данных в табличном представлении зачастую не обходится без разбиения на части. Ведь одна таблица может содержать огромное количество записей. В таком случае проблему ее «листания» приходится решать вручную, причем использования для этого традиционного способа — далеко не самое приятное занятие. В объекте DataGrid предусмотрено и это. Смотрите сами:
<%@ language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.ADO" %>
<script language="VB" runat="server">
Sub Page_Load(sender As Object, e As EventArgs)
BindGrid
End Sub
Sub changePage(sender As Object, e As DataGridPageChangedEventArgs)
BindGrid
End Sub
Sub BindGrid()
Dim ds As DataSet
Dim cnn As ADOConnection
Dim cmd As ADODataSetCommand
cnn = New ADOConnection("dsn=sample")
cmd = New ADODataSetCommand("select * from Authors", cnn)
ds = new DataSet()
cmd.FillDataSet(ds, "Authors")
Grid1.DataSource=ds.Tables("Authors").DefaultView
Grid1.DataBind()
End Sub
</script>
<form runat="server">
<ASP:DataGrid id="Grid1" runat="server" AllowPaging="True" PageSize="10" PageCount="1"
PagerStyle-Mode="NumericPages" PagerStyle-HorizontalAlign="Right"
OnPageIndexChanged="changePage"
/>
</form>
Попробуем отобразить таблицу, но так, чтобы при этом можно было ее редактировать. Для обычного ASP задача далеко не тривиальная, требующая обработки не одной формы. Посмотрите и оцените сами, как просто эта задача решается с помощью ASP+:
<%@ language="vb" %>
<%@ import namespace="system.data" %>
<%@ import namespace="system.data.ado" %>
<script language="vb" runat="server">
dim cnn as adoconnection
dim cmd as adodatasetcommand
dim ds as new dataset
public sub page_load(sender as object,e as eventargs)
if page.ispostback=false then
BindGrid()
end if
end sub
public sub BindGrid()
cnn=new adoconnection("dsn=sample")
cmd=new adodatasetcommand("select * from authors",cnn)
cmd.filldataset(ds,"authors")
grid1.datasource=ds.tables("authors").defaultview
grid1.databind()
end sub
public sub EditRow(sender as Object, e as DataGridCommandEventArgs)
grid1.EditItemIndex = e.Item.ItemIndex
BindGrid()
end sub
public sub CancelUpdate(sender as Object, e as DataGridCommandEventArgs)
grid1.EditItemIndex = -1
BindGrid()
end sub
public sub DeleteRow(sender as Object,e as DataGridCommandEventArgs)
end sub
public sub UpdateRow(sender as Object,e as DataGridCommandEventArgs)
dim txt1 as textbox
dim txt2 as textbox
txt1=e.Item.FindControl("txtAuthor")
txt2=e.Item.FindControl("txtYear")
end sub
</script>
<form runat=server>
<asp:datagrid id="grid1" runat="server"
OnEditCommand="EditRow"
OnCancelCommand="CancelUpdate"
OnUpdateCommand="UpdateRow"
OnDeleteCommand="DeleteRow"
DataKeyField="au_id"
AutoGenerateColumns="false" >
<property name="Columns">
<asp:EditCommandColumn EditText="Edit" CancelText="Cancel" UpdateText="Update" />
<asp:BoundColumn Headertext="ID" DataField="au_id" ReadOnly="true"/>
<asp:TemplateColumn headertext="Name">
<template name="ItemTemplate">
<asp:Label Text='<%# Container.DataItem("au_lname") %>' runat="server"/>
</template>
<template name="EditItemTemplate">
<asp:TextBox id="txtAuthor" Text='<%# Container.DataItem("au_lname") %>' runat="server"/>
</template>
</asp:TemplateColumn>
<asp:TemplateColumn headertext="Year Born">
<template name="ItemTemplate">
<asp:Label Text='<%# Container.DataItem("phone") %>' runat="server"/>
</template>
<template name="EditItemTemplate">
<asp:TextBox id="txtYear" Text='<%# Container.DataItem("phone") %>' runat="server"/>
</template>
</asp:TemplateColumn>
</property>
</asp:datagrid>
</form>
Объяснения излишни: код говорит сам за себя. Пожалуй, это основное достоинство ASP+ — «красноречивость» кода. Попробуйте скопировать его в .aspx-файл и выполнить. Поверьте, результат и то, какими небольшими усилиями он может быть достигнут, вас приятно удивит.
Как видите, все довольно просто, однако эта простота обусловлена наличием в ASP+ богатой палитры визуальных компонентов, позволяющих заменять целые группы обычных HTML-компонентов, использовавшихся в обычном ASP. Достоинство этих компонентов (в данном случае, например, компонентов DataList или DataGrid) заключается не только в визуализации разнообразных данных и процессов, но и в богатых возможностях обработки событий, наличия огромного количества типовых решений и всевозможных шаблонов для выполнения типовых операций и т.д. И это еще одно преимущество ASP+.
КомпьютерПресс 3'2001