Основы ASP.NET 2.0

         

Элементы-источники данных (Data Source Controls)


Эти элементы облегчают работу с ADO .NET, инкапсулируя работу с соединениями, командами и адаптерами. Они реализуют интерфейс IDataSource, в котором определен базовый набор возможностей работы с источниками данных. Большинство этих классов предоставляют функциональность для чтения и записи. Они являются обертками объектов ADO .NET. В предыдущих версиях надо было создавать объекты ADO самим и связывать элементы-управления с ними посредством команды DataBind. Например:

<asp:BulletedList ID="BulletedList1" runat="server" BulletStyle="Square" DataTextField="CategoryName" DataValueField="CategoryID"> </asp:BulletedList>

protected void Page_Load(object sender, EventArgs e) { SqlConnection conn = new SqlConnection(@"Data Source=(local)\sqlexpress;Initial Catalog=Northwind;Integrated Security=True"); SqlCommand cmd = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories", conn); SqlDataAdapter da = new SqlDataAdapter(cmd); DataSet ds = new DataSet(); da.Fill(ds); BulletedList1.DataSource = ds; BulletedList1.DataBind(); }

Теперь элементы управления связываются c элементом-источником посредством свойства DataSourceID. Любой класс-источник данных может быть связан почти с любым классом для отображения данных, и это предоставляет большую гибкость.

Всего в ASP .NET 5 элементов-источников данных: SqlDataSource, AccessDataSource и ObjectDataSource для работы с табличными источниками данных и XmlDataSource и SiteMapDataSource — для работы с иерархическими данными.


SqlDataSource позволяет соединяться с большинством реляционных СУБД. Sql в названии класса означает, что служит для соединения с базами, которые понимают язык запросов Sql, а не только с MS SQL Server.

AccessDataSource оптимизирован для работы с базами Access. Например:

<asp:AccessDataSource ID="AccessDataSource1" runat="server" DataFile="~/App_Data/guestbook.mdb" SelectCommand="SELECT [WriteDate], [UserName], [UserMail], [Message] FROM [guestbook]"> </asp:AccessDataSource>

SiteMapDataSource — это специализация XmlDataSource, работает с файлами навигации по сайту и служит источником данных для элементов управления навигации.

ObjectDataSource нужен для соединения с написанными программистом бизнес-объектами.

Элементы-источники данных предназначены для двустороннего обмена данными, то есть как для чтения, так и для записи. Сами по себе они ничего не отображают. Данные будут доступны подключенным к ним элементам управления.


Кэширование


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

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

В SqlDataSource кэширование и сортировка возможны только при получении данных через DataSet. Если DataSourceMode равно DataReader, а EnableCaching — True, будет выброшено исключение NonSupportedException.

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

Поведение кэширования зависит от сочетания свойств CacheDuration и CacheExpirationPolicy. Если значение CacheExpiration Policy равно Absolute, то элемент запрашивает информацию через промежутки времени, определенные в CacheDuration, а старую стирает из памяти. Если CacheExpirationPolicy равен значению Sliding, то SqlDataSource начинает отсчет времени после каждого запроса к нему. Данные из кэша устаревают, если в течение времени CacheDuration не было ни одного Select-запроса.

В FilterExpression задается выражение для фильтрации, причем формат этих выражений аналогичен тому, что используется для форматирования строк с параметрами в фигурных скобках {0}, {1}, в которые подставляются значения из источника, указанного в Filter Parameters:


<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT * FROM [Customers]" ProviderName="<%$ ConnectionStrings:NorthwindConnectionString.ProviderName %>" EnableCaching="True" CacheExpirationPolicy="Sliding"> </asp:SqlDataSource>

У этого элемента включено кэширование, и он является источником данных для GridView.

<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT * FROM [Customers]" ProviderName="<%$ ConnectionStrings:NorthwindConnectionString.ProviderName %>" FilterExpression="CustomerID=’{0}’ " <FilterParameters> <asp:ControlParameter Name="CustomerID" ControlId="GridView1" PropertyName="SelectedValue"></asp:ControlParameter> </FilterParameters> </asp:SqlDataSource>

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


Объектная модель источников данных


"Прежде всего нужны факты, а уж потом можно делать с ними, что хочешь."

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

В Visual Studio .NET 2002 и 2003 можно было создавать привязки данных к странице по технологии "drag-and-drop". Эта технология была удобна тем, что упрощала написание кода, но вместе с тем она усложняла его модификацию. Объекты данных DataAdapter и DataConnection напрямую связывались Visual Studio 2005 формой. Сейчас это тоже возможно, но технология изменилась. Введена новая объектная модель источников данных. Классы-источники данных обеспечивают лучшую абстрактизацию, чем использование классов ADO.

Один из компонентов этой модели — строка соединения с источником данных. В Visual Studio 2005 все строки добавляются в конфигурационный файл web.config:



<configuration> <appSettings/> <connectionStrings> <add name="DemoBaseConnectionString1" connectionString="Data Source= \SQLEXPRESS;Initial Catalog=DemoBase;Integrated Security=True" providerName="System.Data.SqlClient" /> <add name="DatabaseConnectionString1" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename="C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\QuickStart\aspnet\sam- ples\data\App_Data\Database.mdf";Integrated Security=True;Connect Timeout=30;User Instance=True" providerName="System.Data.SqlClient" /> </connectionStrings>


Разные страницы могут использовать одну и ту же строку соединения. Если по какой-либо причине соединение нужно будет изменить, например, если сервер изменил свое местоположение, изменения придется вводить централизованно в файле web.config.

Окно Data WebMatrix позволяет соединяться только с базами Access и SQL Server. Также работает перетаскивание, но требуется, чтобы в таблице имелся первичный ключ. Он не поддерживает и представлений (View) Access.

В WebMatrix существуют собственные элементы управления с префиксом wmx — AccessDataSourceControl и SqlDataSourceControl. Строка соединения записывается в свойство ConnectionString такого элемента управления. Программа WebMatrix служила испытательным полигоном для тех новых возможностей, которые позже были добавлены в Visual Studio .NET 2005:

<wmx:AccessDataSourceControl id="AccessDataSourceControl1" runat="server" ConnectionString="Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=D:\My_DOCs\guestbook.mdb" SelectCommand="SELECT * FROM [guestbook]"></wmx:AccessDataSourceControl> <wmx:SqlDataSourceControl id="SqlDataSourceControl1" runat="server" ConnectionString="server='SQLEXPRESS'; trusted_connection=true; database='Northwind'" SelectCommand="SELECT * FROM [Categories]" DeleteCommand="" UpdateCommand=""></wmx:SqlDataSourceControl>

Итак, строка соединения состоит из указания провайдера, если это Oledb, сервера и базы на этом сервере.



База может находиться в отдельном файле с расширением .mdf. При соединении через ODBC указывается имя источника данных, тип базы, путь к файлу и драйвер:

<add name="ConnectionString1" connectionString="DSN=BB;DBQ=D:\Programming\Brain- bench\brainbench.mdb;DriverId=25;FIL=MS Access;MaxBufferSize=2048;PageTimeout=5;" providerName="System.Data.Odbc" />

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

Строками соединений можно манипулировать и программно:

protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { // Создание класса ConnectionStringSettings ConnectionStringSettings conn = new ConnectionStringSettings(); conn.ConnectionString = "Server=localhost; " + "User ID=sa;Password=m1d2ffnkl; " + "Database=Northwind;Persist Security Info=True"; conn.Name = "Northwind ConnectionString"; conn.ProviderName = "System.Data.SqlClient"; //Добавление строки в файл web.config ConfigurationManager.ConnectionStrings.Add(conn); } }


ObjectDataSource


Как уже было сказано, этот класс работает с бизнес-объектами. А что же это такое? Это такие классы, которые инкапсулируют логику работы с данными, нужными в приложении. Класс бизнес-объекта может быть написан на любом языке .NET. Как и все классы, он располагается в папке App_Code. ObjectDataSource работает как связующее звено между бизнес-объектами и элементами управления, отображающими данные. Получается многоуровневая компонентная архитектура. Классы бизнес-объектов могут поменять свое внутреннее представление, и это никак не отразится на страницах, которые их используют. ObjectDataSource работает во многом так же, как SqlDataSource, с той разницей, что он имеет дело не с базой данных, а с классом.

Свойство TypeName класса ObjectDataSource указывает на используемый класс. Класс бизнес-объекта должен поддерживать конструктор и 4 метода (возможно, и больше) — для чтения, редактирования, удаления и добавления данных в источник данных. Элемент управления ObjectDataSource пользуется этими методами.

Например, свойство SelectMethod указывает на метод класса бизнес-объекта, который возвращает данные.

Откуда бизнес-объект берет данные, ему не важно. Некоторые бизнес-объекты работают с базами данных, некоторые — с сессией или текстовыми файлами. Главное, что метод, который он использует для чтения, должен возвращать класс, реализующий интерфейс IEnumerable. UpdateMethod — метод, который обновляет данные. Аналогичную функцию выполняют DeleteMethod и InsertMethod.

Класс бизнес-объекта может поддерживать метод SelectCount, который возвращает общее количество объектов в источнике данных.


ObjectDataSource вызывает этот метод, чтобы реализовать разбиение на страницы.

Рассмотрим это на примере:

public class Continent { ArrayList ContinentArrayList; public Continent() { ContinentArrayList = new ArrayList(); ContinentArrayList.Add("Worldwide"); ContinentArrayList.Add("America"); ContinentArrayList.Add("Africa"); ContinentArrayList. Add("Asia-Pacific");

} public ArrayList List() { return ContinentArrayList; } public int SelectCount() { return ContinentArrayList.Length; } }

Даже такой примитивный класс может использоваться как источник данных для ObjectDataSource, так как ArrayList реализует IEnumerable. Вместо свойств *Command ObjectDataSource использует *Method:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="List" TypeName=" Continent "> </asp:ObjectDataSource> <asp:RadioButtonList ID="RadioButtonList1" runat="server" DataSourceID="ObjectDataSource1"> </asp:RadioButtonList></div>

Достигается тот же эффект, что и раньше, когда данные вставлялись на странице или в классе страницы, но теперь получение данных инкапсулировано в классе Continent. Класс может изменить способ получения данных, не меняя интерфейса. Чаще всего данные все-таки получают из баз данных, XML-файлов или web-сервисов. Классы бизнес-логики могут разрабатывать одни члены команды, а заниматься дизайном страниц — другие. Их можно использовать и в обычных приложениях в Windows Forms.



ObjectDataSource может работать и с типизированными наборами данных, которые можно создать с помощью мастера. Попробуем это сделать на примере таблицы Customers. Создайте в папке App_Code новый файл и в диалоге выбора типа файла выберите dataset. Назовите его Customers. Мастер предложит выбрать строку соединения. Выберите NorthWindConnectionString (если его нет в проекте, создайте, как показано в предыдущей лекции). На следующем шаге мастер предложит выбрать из трех вариантов: использование запросов SQL, создание хранимых процедур или использование готовых процедур. Выберите второе, так как готовых процедур, которые бы обновляли данные, в базе Northwind нет. На следующем шаге нужно будет создать процедуры, это можно сделать с помощью QueryBuilder, очень похожем на дизайнер запросов в MS Access. В списке таблиц выберите Customers, а в таблице несколько полей. Должен получиться запрос

SELECT CustomerID, CompanyName, ContactName, ContactTitle, Country, City FROM Customers



После этого проект желательно скомпилировать.

Мы получили компонент данных. Все готово для связывания его с ObjectDataSource. Перетащите значок нужного класса на форму и с помощью SmartTag запустите еще один мастер. На первом шаге настройте его на CustomersDataAdapters.CustomersDataAdapter. На втором надо выбрать подходящие функции для команд Select, Update, Delete, Insert. Вариантов будет немного — после выбора нажмите Finish. Можно привязывать наш ObjectDataSource к любому подходящему элементу управления, например, GridView:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetData" TypeName="CustomersTableAdapters.CustomersTableAdapter" DeleteMethod="Delete" InsertMethod="Insert" OldValuesParameterFormatString="original_{0}" UpdateMethod="Update"> <DeleteParameters> <asp:Parameter Name="Original_CustomerID" Type="String" /> </DeleteParameters> <UpdateParameters> <asp:Parameter Name="CustomerID" Type="String" /> <asp:Parameter Name="CompanyName" Type="String" /> <asp:Parameter Name="ContactName" Type="String" /> <asp:Parameter Name="ContactTitle" Type="String" /> <asp:Parameter Name="Country" Type="String" /> <asp:Parameter Name="City" Type="String" /> <asp:Parameter Name="Original_CustomerID" Type="String" /> </UpdateParameters> <InsertParameters> <asp:Parameter Name="CustomerID" Type="String" /> <asp:Parameter Name="CompanyName" Type="String" /> <asp:Parameter Name="ContactName" Type="String" /> <asp:Parameter Name="ContactTitle" Type="String" /> <asp:Parameter Name="Country" Type="String" /> <asp:Parameter Name="City" Type="String" /> </InsertParameters> </asp:ObjectDataSource> <asp:GridView ID="GridView1" runat="server" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False" DataKeyNames="CustomerID" DataSourceID="1"> <Columns> <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" ShowSelectButton="True" /> <asp:BoundField DataField="CustomerID" HeaderText="CustomerID" ReadOnly="True" SortExpression="CustomerID" /> <asp:BoundField DataField="CompanyName" HeaderText="CompanyName" SortExpression="CompanyName" /> <asp:BoundField DataField="ContactName" HeaderText="ContactName" SortExpression="ContactName" /> <asp:BoundField DataField="ContactTitle" HeaderText="ContactTitle" SortExpression="ContactTitle" /> <asp:BoundField DataField="Country" HeaderText="Country" SortExpression="Country" /> <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" /> </Columns> </asp:GridView>



Класс бизнес- объекта создается неявно. Из файла .xsd можно получить класс типизированного набора данных на языке C# с помощью утилиты xsd.exe.

xsd.exe /dataset /language:CS Customers.xsd.

Из одного класса могут получать данные разные элементы Object DataSource. В приложении Personal Starter Kit определен класс Photo Manager, который работает с базой данных Personal.mdf:

public static Stream GetPhoto(int photoid, PhotoSize size) { using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Personal"].C onnectionString)) { using (SqlCommand command = new SqlCommand("GetPhoto", con- nection)) { command.CommandType = CommandType.StoredProcedure; command.Parameters.Add(new SqlParameter("@PhotoID", photoid)); command.Parameters.Add(new SqlParameter("@Size", (int)size)); bool filter = !(HttpContext.Current.User.IsInRole("Friends") || HttpContext.Current.User.IsInRole("Administrators")); command.Parameters.Add(new SqlParameter("@IsPublic", filter)); connection.Open(); object result = command.ExecuteScalar(); try { return new MemoryStream((byte[])result); } catch { return null; } } }

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


Сортировка


В свойстве SortParameterName можно записать список полей, по которым проводится сортировка, возможно с добавлением опции Desc для сортировки в порядке убывания. Параметры передаются в команду Select, если это серверная процедура.



SqlDataSource


SqlDataSource объединяет в себе возможности SqlConnection и SqlDataAdapter (плюс дополнительные).

Итак, у нас есть строка подключения в файле web.config:

<add name="DemoBaseConnectionString1" connectionString="Data Source=(local)\SQLEXPRESS;Initial Catalog=DemoBase;Integrated Security=True" providerName="System.Data.SqlClient" />

В свойство ConnectionString записывается эта строка:

<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:DemoBaseConnectionString1 %>" ProviderName="<%$ ConnectionStrings:DemoBaseConnectionString1.ProviderName %>" </asp:SqlDataSource>

В свойстве DataSourceMode SqlDataSource задается, посредством DataReader или DataSet получаются данные. При чтении посредством DataReader некоторые возможности не поддерживаются.

Получение данных связано со свойствами, похожими на свойства SqlDataAdapter: SelectCommand, SelectCommandType, DeleteCommand, DeleteCommandType и так далее. SelectCommandType может быть 2 типов — Text и StoredProcedure. Команды выполняются, когда вызываются соответствующие методы.

Метод Select вызывается с параметром типа DataSourceSelectArguments и возвращает DataSet или IDataReader в зависимости от значения свойства DataSourceMode, остальные же методы вызываются без параметров и возвращают количество обработанных строк:

<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT * FROM [Customers]" ProviderName="<%$ ConnectionStrings:NorthwindConnectionString.ProviderName %>"> </asp:SqlDataSource>


Этот SqlDataSource читает все записи из таблицы Customers с помощью простого запроса в DataSet:

<asp:SqlDataSource ID="SqlDataSource3" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="[Ten Most Expensive Products]" DeleteCommandType="StoredProcedure"> </asp:SqlDataSource>

Метод Select нет необходимости вызывать явно. Он вызывается автоматически, когда связанному с SqlDataSource элементу нужны данные для отображения.

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

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

Есть несколько классов параметров — наследников класса Parameter: CookieParameter использует значение ключа файла cookie, FormParameter — переменных формы, QuerystringParameter — адресной строки, ProfileParameter — профиля пользователя и SessionParameter — переменной сессии:

<asp:Parameter Name="UID" Type="Int32" DefaultValue="0" />

Такой тип параметров применяется, если SqlDataSource используется как источник данных для элементов с автоматическим связыванием — GridView, FormView, DetailsView. Значение параметра передается во "внутренностях" этих элементов.

В других случаях задействуется ControlParameter, то есть значение параметра берется из элемента управления.



Также задается свойство, откуда и берется значение. Хотя если это Text, его можно не писать:

<asp:SqlDataSource ID="SqlDataSource3" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="Sales by Year" SelectCommandType="StoredProcedure"> <SelectParameters> <asp:Parameter Name="Beginning_Date" Type="DateTime" DefaultValue="01.01.1998"/> <asp:ControlParameter Name="Ending_Date" Type="DateTime" ControlID="Calendar2"/> </SelectParameters> </asp:SqlDataSource>

Источник параметра типа "Дата" — элемент управления "Календарь". При заданном свойстве параметра ConvertEmptyToNull текстовый параметр конвертируется в Null, если он пустой (равен System. String.Empty).

Свойство CancelSelectOnNullParameter определяет, будет ли прерван запрос, если значение какого-либо параметра равно Null:

<asp:SqlDataSource ID="SqlDataSource4" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT * FROM [Customers] where @Country is null or Country = @Country" ProviderName="<%$ ConnectionStrings:NorthwindConnectionString.ProviderName %>" CancelSelectOnNullParameter="False"> <SelectParameters> <asp:QueryStringParameter Name="Country" QueryStringField="Country" /> </SelectParameters> </asp:SqlDataSource>

Этот запрос будет брать параметр из командной строки, например

http://localhost:3457/WebSite4/CustomersByCountry.aspx?Country=UK


элементы управления, которые отвечают за


Мы рассмотрели классы- элементы управления, которые отвечают за получение данных. Эти классы предназначены в первую очередь для облегчения труда программиста (по сравнению с предыдущими версиями). Наиболее простые страницы с помощью этих элементов создаются даже без написания программного кода. В следующих двух лекциях подробнее займемся отображением данных. XMLDataSource будет рассмотрен в лекции 10, а SiteMapSource — в лекции 11.