Китай |
Управление состоянием страниц на клиенте
Упражнение 12. Хранение данных в статических переменных приложения
Для увеличения масштабируемости приложение загружается в память сервера в виде множества копий (pool - пул), представляющих собой экземпляры (объекты) класса приложения. Каждый экземпляр класса приложения имеет свой (экземплярный) набор данных и только объект-тип хранит все методы и статические данные в единственном экземпляре. Если в файле Global.asax объявить общедоступные статические поля, то в них можно хранить данные, которые будут видимы через имя класса приложения из любой страницы сайта любого экземпляра в рамках пула. Но при этом нужно явно определить в директиве @ Application файла Global.asax параметр ClassName, в котором указывается имя класса приложения для последующего обращения из кода страниц.
При изменении в страницах глобальных данных класса приложения механизм автоматической блокировки отсутствует. Поэтому нужно пользоваться встроенным в язык C# оператором lock, чтобы на время позволить воздействовать на переменную только со стороны одного объекта приложения или одного потока, если применяется многопоточная модель. Такой подход удобен тем, что мы можем обернуть сохраняемые данные в статические свойства и назначить для них контролирующий код, прежде чем сохранять их в памяти сервера. Мы можем объявлять статические переменные для хранения объектов любого типа и для доступа к ним явных преобразований типа не потребуется.
Приведем пример, в котором количество визитов всех пользователей, а также список файлов текущего физического корневого каталога сервера будем хранить в статических переменных класса приложения.
- Отредактируйте код файла Global.asax следующим образом
<%@ Application Language="C#" ClassName="MyAppClass" %> <script runat="server"> // Список файлов private static string[] fileList;// Базовое поле // Общедоступное статическое свойство для обертки базового поля public static string[] FileList { get { // Заполнить список только при первом запросе if (fileList == null) { fileList = System.IO.Directory.GetFiles( HttpContext.Current.Request.PhysicalApplicationPath); } return fileList; } } // Число посещений private static int visit = 1;// Базовое поле // Общедоступное статическое свойство для обертки базового поля public static int Visit { get { return visit; } set { lock (typeof(int))// Контейнер обеспечения синхронизации потоков { visit = value; } } } </script>Листинг 35.27. Код файла Global.asax со статическими членами
- Добавьте к приложению страницу без отделенного кода с именем AppClassStaticMembers.aspx и назначьте ее стартовой
- Заполните страницу AppClassStaticMembers.aspx следующим кодом
<%@ Page Language="C#" EnableViewState="false" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { // Заголовок Label title = new Label(); form1.Controls.Add(title); title.Text = "<h2 style='text-align: center; color: Red'>" + "Использование статических" + " полей класса приложения</h2>"; // Число посещений Label visit = new Label(); form1.Controls.Add(visit); int clicks = MyAppClass.Visit; visit.Text = "<b>Количество посещений: " + clicks.ToString() + "</b>"; MyAppClass.Visit = ++clicks; // Горизонтальная черта form1.Controls.Add(new HtmlGenericControl("hr")); // Извлекаем и готовим список файлов // текущего каталога приложения StringBuilder builder = new StringBuilder(); builder.Append("<ol>"); // Счетчик для сокращения листинга int count = 0; const int maxCount = 5; foreach (string file in MyAppClass.FileList) { if (++count > maxCount) break; string str; //int pos = file.LastIndexOf(@"\"); //str = file.Substring(pos + 1); // То же самое str = System.IO.Path.GetFileName(file); builder.Append("<li>" + str + "</li>"); } builder.Append("</ol>"); // Готовим текстовую метку для отображения списка Label fileInfo = new Label(); form1.Controls.Add(fileInfo); fileInfo.Text = builder.ToString(); // Горизонтальная черта form1.Controls.Add(new HtmlGenericControl("hr")); // Создаем дескриптор центрирования кнопки HtmlGenericControl center = new HtmlGenericControl("center"); form1.Controls.Add(center); // Кнопка Submit добавляется в контейнер центрирования Button button = new Button(); button.Text = "Отправить"; center.Controls.Add(button); } // Переопределяем обработчик рендеринга protected override void Render(HtmlTextWriter writer) { // Сгенерировать основное base.Render(writer); // Добавить в конец еще HTML-вывод // Настроить атрибуты будущего дескриптора writer.AddAttribute(HtmlTextWriterAttribute.Align, "Center"); writer.AddStyleAttribute(HtmlTextWriterStyle.Color, "Blue"); // Создать дескриптор writer.RenderBeginTag(HtmlTextWriterTag.H2); // Писать внутрь дескриптора writer.Write("Щелкайте на кнопке и наблюдайте счетчик посещений"); // Закрыть дескриптор writer.RenderEndTag(); } </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> </form> </body> </html>Листинг 35.28. Код страницы AppClassStaticMembers.aspx
- Запустите страницу и убедитесь, что все работает и объявленные в классе приложения статические члены сохраняют свои значения даже при отключении клиента от сервера до тех пор, пока сервер остается запущенным
- В панели задач нижней части экрана щелкните правой кнопкой мыши на пиктограмме тестового сервера и остановите его командой Stop
- Вновь запустите страницу AppClassStaticMembers.aspx, чтобы убедиться, что память сервера очистилась и счетчик сбросился в начальное значение
А сейчас мы убедимся, что при модификации любого файла приложения, включая web.config, оно автоматически перекомпилируется при первом запросе и загружается в новый домен.
- Не нарушая кода, модифицируйте любой исходный файл приложения, например, введите пробел после точки с запятой в конце любой строки (или добавьте пустую строку) и сохраните изменения
- Запустите приложение и убедитесь, что счетчик сбросился за счет загрузки приложения в новый домен
Интерфейс клиента для данного примера будет таким
Рассмотренные в данной теме способы хранения данных относятся, в основном, к внутрипроцессным, так как сохраняются в оперативной памяти сервера или передаются по каналам связи на компьютер клиента для временного хранения. Другие методы хранения информации в службах сервера, включая базы данных и файлы, являются внепроцессными, поскольку не зависят от среды исполнения ASP.NET. Но мы их здесь не рассматривали.