Исходники.Ру - Программирование
Исходники
Статьи
Книги и учебники
Скрипты
Новости RSS
Магазин программиста

Главная » Статьи по программированию » .NET - Все статьи »

Обсудить на форуме Обсудить на форуме

Использование Web User Controls для построения шаблонов страниц в ASP.Net
В статье рассматривается методика построения системы шаблонов страниц сайта в ASP.Net, основанная на применении пользовательских компонентов (Web User Controls). Приложение к статье - исходный код простого сайта, иллюстрирующий особенности указанной методики.
В статье рассматривается методика построения системы шаблонов страниц сайта в ASP.Net, основанная на применении пользовательских компонентов (Web User Controls). Приложение к статье - исходный код простого сайта, иллюстрирующий особенности указанной методики.

Описание проблемы

При создании сайта веб-дизайнер и/или программист сталкивается с проблемой разделения общей (для многих страниц) и частной (для конкретных страниц) информации. Общая информация - это модульная сетка сайта (разбиение страниц на отдельные блоки, например, верхнее меню, левое меню, центральная часть), листы стилей CSS, метаданные (ключевые слова, описание и пр.), скрипты (JavaScript, VBScript), информационные блоки, например, на всех страницах сайта в нижней части может отображаться контактная информация, и т. д. Частная информация конкретной страницы - это заголовок страницы, информация, размещаемая в ее центральной части, например, простой текст или форма для ввода данных, и т.д. Часто об общей информации говорят, что она представляет собой шаблон страниц сайта, а частная информация каждой страницы - конкретное содержание используемого шаблона.

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

Существуют различные реализации систем для построения сайтов с применением технологии шаблонов. Подобные системы иногда называют web framework, правда, кроме шаблонов web framework содержит массу дополнительных возможностей, в частности, разделение html-кода и программного кода, MVC-архитектура, дополнительные функциональные сервисы и API и т.д. В наиболее распространенных технологиях, используемых в настоящее время для создания веб-приложений, можно отметить несколько вариантов web framework. Например, в Java используются такие системы, как Struts Tiles, Jakarta Turbine, JPublish и др. В PHP это Roadsend Site Mananager, Smarty, FastTemplate и др. В ASP это ASP Template и др.

Примечательно, что в базовых технологиях JSP, PHP, ASP отсутствует какая-либо встроенная стандартная реализация системы шаблонов - производители почему-то ограничиваются предложением использовать различные варианты Server Side Includes.

Например, в JSP используются:

<jsp:include page="{relativeURL | <%= expression %>}" flush="true| false" />

или

<%@ include file="relativeURL" %>.

В PHP это выглядит так:

<?php include 'filename'; ?>.

В ASP используются:

<!--#include virtual = "filename"-->

или

<!--#include file = "filename"-->.

Следует отметить, что Server Side Includes не являются системой шаблонов в полном смысле, в частности, SSI не позволяют избежать дублирования информации о модульной сетке сайта. Тем более удивительно, что при очевидной важности шаблонов производители не предлагают стандартной реализации для каждой технологии - все отмеченные выше системы шаблонов для JSP, PHP и ASP разработаны либо в рамках движения open source (www.sourceforge.net), либо сторонними фирмами.

Интересно, что ситуация с шаблонами в ASP.Net не слишком отличается от JSP, PHP, ASP. Проблема та же самая - в текущей версии ASP.Net нет стандартного механизма построения шаблонов страниц, который был бы рекомендован Microsoft и поддерживался бы на уровне среды разработки Visual Studio.Net. Возможно, в версии ASP.Net 2.0 подобный механизм будет предложен, но пока приходится использовать различные частные решения.

В качестве таких решений в настоящее время разными разработчиками предлагается использовать Server Side Includes (директивы включения ASP остаются работоспособными и в ASP.Net), наследование страниц ASP.Net с переписыванием метода Page.Render, включение пользовательских компонентов (Web User Controls) в страницу.

Метод наследования страниц ASP.Net предполагает внедрение html-кода в программный код, соответственно исключает всякую возможность визуального редактирования шаблона страницы, чреват ошибками и не слишком удобен при сопровождении сайта.

В случае использования пользовательских компонентов получаем фактически более интеллектуальный аналог Server Side Includes - компоненты могут содержать не просто статическую информацию, но и некоторую программную логику. Заметим, что простое включение компонентов не решает проблему вынесения модульной сетки сайта в шаблон страницы, хотя и является существенным шагом вперед к созданию полноценной системы шаблонов.

Решение проблемы

Рассмотрим минимальные требования, которым должна удовлетворять система шаблонов страниц ASP.Net:

  • На сайте может использоваться произвольное количество шаблонов страниц.
  • Должен обеспечиваться режим визуального редактирования любых составляющих шаблона страницы в текущей версии Visual Studio .Net.
  • Система шаблонов должна быть достаточно простой для освоения ее веб-дизайнером.
  • В простом варианте система шаблонов не должна требовать использования базы данных для хранения информации о страницах и шаблонах.
  • Система шаблонов должна естественным образом встраиваться в модель ASP.Net и не должна ограничивать возможности разработчика по применению существующих технологий, т.е. должны сохраняться возможности использования директив включения Server Side Includes, веб-компонентов и т.д.

Предлагаемое решение для построения шаблонов удовлетворяет указанным требованиям и базируется на использовании пользовательских компонентов (Web User Controls) как для построения шаблонов страниц, так и для формирования содержимого конкретных страниц.

Методику построения шаблонов изложим на примере простого сайта, включающего:

  • один общий шаблон для всех страниц, включающий верхнюю часть, левую часть, центральную часть и нижнюю часть;
  • главную страницу, на которой отображаются последние новости;
  • страницу для добавления новостей;
  • статическую страницу, содержащую простой текст.

Кроме того, в примере рассматривается использование пользовательского компонента для создания шаблона левого меню навигации с целью иллюстрации дополнительных возможностей рассматриваемой методики. Исходные тексты примера приводятся в качестве приложения к статье.

Основной шаблон страниц сайта хранится в каталоге Templates и представляет собой пользовательский компонент DefaultTemplate.ascx с программным модулем DefaultTemplate.ascx.cs. Рассмотрим содержание соответствующих файлов.

Templates/DefaultTemplate.ascx

<%@ Control Language="c#" AutoEventWireup="false" Codebehind="DefaultTemplate.ascx.cs" 
		Inherits="GotDotNetTemplates.Templates.DefaultTemplate" 
		TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
  <head>
    <title><% = Title %></title>
    <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
    <meta http-equiv="description" content="Здесь сейчас статическое описание, 
			не трудно представить, как сделать динамическое - См. Title">
    <meta http-equiv="keywords" content=".Net, ASP.Net, C#, шаблоны страниц, 
			Templates, User Control ">
    <link href="<%=Request.ApplicationPath%>/Styles/Default.css" 
			type="text/css" rel="stylesheet">
  </head>
<body>
  <form id="Default" method="post" runat="server">
    <table cellSpacing="1" cellPadding="1" width="100%" border="1">
      <tr>
        <td noWrap align="middle" colspan="2">
          <!--<Верхняя часть>-->
          <p>Здесь в шаблоне размещается верхняя часть страницы (рекламный блок, меню 
             навигации и пр.)</p>
          <!--</Верхняя часть>-->
        </td>
      </tr>
      <tr>
        <td noWrap width="20%" valign="top">
          <!--<Левая часть>-->
          <asp:PlaceHolder id="LeftPlaceHolder" runat="server"></asp:PlaceHolder>
          <!--</Левая часть>-->
        </td>
        <td noWrap width="80%" valign="top">
          <!--<Центральная часть>-->
          <asp:placeholder id="CenterPlaceHolder" runat="server"></asp:placeholder>
          <!--</Центральная часть>-->
        </td>
      </tr>
      <tr>
        <td noWrap align="middle" colspan="2">
          <!--<Нижняя часть>-->
          <p>Здесь в шаблоне размещается нижняя часть страницы (контактная информация, 
          информация о разработчиках и пр.)</p>
          <!--</Нижняя часть>-->
        </td>
      </tr>
    </table>
  </form>
</body>
</html>

Пользовательский компонент DefaultTemplate.ascx включает в себя html-теги верхнего уровня, в том числе <html>, <head>, <body>, <form>, то есть те теги, которые обычно характерны не для компонентов, а для страниц ASP.Net. В этом заключается основная особенность данного способа построения шаблонов. Обратите внимание, что в теге <form> отсутствует атрибут action, его вставляет среда выполнения при окончательном формировании страницы. Подробнее об этом будет написано ниже при рассмотрении кода главной страницы.

В шаблоне определены следующие области, данные для которых предоставляются страницами, использующими шаблон:

  • заголовок страницы - для вывода используется свойство Title компонента
    <title><% = Title %></title>
    
  • левая часть - в эту область шаблона может загружаться любой пользовательский компонент, в качестве контейнера используется PlaceHolder
              <!--<Левая часть>-->
              <asp:PlaceHolder id="LeftPlaceHolder" runat="server"></asp:PlaceHolder>
              <!--</Левая часть>-->
    
  • центральная часть - аналогична левой части в том смысле, что и в нее может загружаться любой пользовательский компонент, в качестве контейнера также используется PlaceHolder
              <!--<Центральная часть>-->
              <asp:placeholder id="CenterPlaceHolder" runat="server"></asp:placeholder>
              <!--</Центральная часть>-->
    

Все прочие области шаблона страницы заданы в нем статически - верхняя часть, нижняя часть, метаданные, ссылка на общий для всех страниц сайта файл с описанием стилевых таблиц Default.css. Последняя ссылка имеет следующий вид:

<link href="<%=Request.ApplicationPath%>/Styles/Default.css" type="text/css" rel="stylesheet">

Шаблон может использоваться в странице сайта, которая находится в каталоге с произвольным уровнем вложенности относительно корневого каталога веб-приложения. Соответственно, в шаблоне необходимо использовать абсолютные ссылки, для этой цели и применяется <%=Request.ApplicationPath%> - возвращает виртуальный путь к корневому каталогу приложения. Например:

<a href="<%=Request.ApplicationPath%>/AddNewsItem.aspx">Добавить новость</a>

Рассмотрим теперь исходный текст программного модуля DefaultTemplate.ascx.cs.

Templates/DefaultTemplate.ascx.cs

public abstract class DefaultTemplate: System.Web.UI.UserControl {
  protected string title;
  protected string leftModuleUrl;
  protected System.Web.UI.WebControls.PlaceHolder LeftPlaceHolder;
  protected System.Web.UI.WebControls.PlaceHolder CenterPlaceHolder;
  protected string centerModuleUrl;

  private void Page_Load(object sender, System.EventArgs e) {
    LeftPlaceHolder.Controls.Add(LoadControl(LeftModuleUrl));			
    CenterPlaceHolder.Controls.Add(LoadControl(CenterModuleUrl));			
  }

  public string Title {
    get { return title; }
    set { title = value; }
  }

  public string LeftModuleUrl {
    get { return leftModuleUrl; }
    set { leftModuleUrl = value; }
  }

  public string CenterModuleUrl {
    get { return centerModuleUrl; }
    set { centerModuleUrl = value; }
  }
}

В классе шаблона определены следующие свойства:

  • Title - заголовок страницы.
  • LeftModuleUrl - url пользовательского компонента, загружаемого в левую часть шаблона.
  • CenterModuleUrl - url пользовательского компонента, загружаемого в центральную часть шаблона.

Применение свойств для определения замещаемых областей в шаблоне является еще одной ключевой особенностью данного способа построения шаблонов. Страницы, использующие шаблон, устанавливают конкретные значения его свойств, формируя таким образом свое содержимое. В шаблоне DefaultTemplate.ascx присутствуют лишь простые строковые свойства, однако, никаких ограничений нет, могут использоваться и сложные типы данных. Пример шаблона, в котором присутствует свойство сложного типа, будет приведен ниже - шаблон левого меню.

Следует отметить, что логика использования свойств шаблона для формирования содержимого страницы программируется в классе шаблона и может быть совершенно произвольной. Например, для загрузки в левую и центральную части шаблона DefaultTemplate.ascx пользовательских компонентов, соответствующих странице, необходимо задать значения строковых свойств LeftModuleUrl, CenterModuleUrl, непосредственная загрузка компонентов осуществляется в методе Page_Load.

Рассмотрим далее применение описанного шаблона в конкретных страницах сайта.

Default.aspx

<%@ Page language="c#" AutoEventWireup="false" %>
<%@ Register TagPrefix="template" 
  TagName="DefaultTemplate"
  Src="Templates/DefaultTemplate.ascx" %>
<template:DefaultTemplate id="DefaultTemplate"
  runat="server" 
  Title="GotDotNetTemplates - Главная страница"
  LeftModuleUrl="~/LeftMenuModule.ascx"
  CenterModuleUrl="~/DefaultCenterModule.ascx">
</template:DefaultTemplate>

На главной странице используется пользовательский компонент шаблона DefaultTemplate.ascx, для которого устанавливаются конкретные значения свойств. Символ "~", используемый при установке значений свойств LeftModuleUrl и CenterModuleUrl, в ASP.Net соответствует корневому каталогу веб-приложения. В левую часть шаблона на главной странице загружается общее для всех страниц сайта меню навигации LeftMenuModule.ascx, а в центральную часть - DefaultCenterModule.ascx, который выводит последние новости из базы данных.

Заметим, что для данного сайта меню навигации могло бы быть просто прописано в шаблоне DefaultTemplate.ascx в виде статического html-кода, и свойство LeftModuleUrl было бы ненужным, однако, в целях иллюстрации потенциальных возможностей я искусственно пошел на дополнительное усложнение шаблона страниц. Практически полезным подобное усложнение будет для сайтов, включающих несколько разделов верхнего уровня, каждый из которых имеет собственное левое меню навигации.

Вернемся теперь к вопросу вставки атрибута action для тега <form>, определенного в шаблоне. Интересная особенность, которая, собственно, и позволяет применять данную методику построения шаблонов, заключается в том, что среда выполнения подставляет в качестве значения атрибута action адрес той aspx-страницы, в которую вставлен пользовательский компонент шаблона. Например, при формировании главной страницы среда выполнения установит значение атрибута action = "/Default.aspx".

AddNewsItem.aspx

<%@ Page language="c#" AutoEventWireup="false"%>
<%@ Register TagPrefix="template" 
  TagName="DefaultTemplate" 
  Src="Templates/DefaultTemplate.ascx" %>
<template:DefaultTemplate id="DefaultTemplate" 
  runat="server"
  Title="GotDotNetTemplates - Добавление новости" 
  LeftModuleUrl="~/LeftMenuModule.ascx"
  CenterModuleUrl="~/AddNewsItemCenterModule.ascx">
</template:DefaultTemplate>

Код страницы для добавления новостей аналогичен коду главной страницы, разница заключается только в устанавливаемых значениях свойств шаблона.

Templates/LeftMenuTemplate.ascx

<%@ Control Language="c#" AutoEventWireup="false" Codebehind="LeftMenuTemplate.ascx.cs" 
			Inherits="GotDotNetTemplates.Templates.LeftMenuTemplate" 
			TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
  <asp:Repeater id="MenuRepeater" runat="server">
  <ItemTemplate>
    <tr>
      <td width="100%" align="left" valign="center" nowrap>
        <img src="<%=Request.ApplicationPath%>/Images/SubmenuPointer.gif" 
				alt="" width="10" height="9" hspace="4" vspace="0" border="0" 
				align="baseline">
        <font class="menu"><a href="<%# DataBinder.Eval(Container, "DataItem.Url") %>">
				<%# DataBinder.Eval(Container, "DataItem.Title") %></a></font>
      </td>
    </tr>
  </ItemTemplate>
  </asp:Repeater>
</table>

В шаблоне левого меню используется Repeater для вывода пунктов меню. В качестве источника данных для Repeater служит обычный ArrayList, который заполняется вспомогательными объектами класса LinkHelper (предназначен для хранения адреса и текста ссылки - Url, Title) - см. ниже.

Templates/LeftMenuTemplate.ascx.cs

public abstract class LeftMenuTemplate: System.Web.UI.UserControl {
  protected System.Web.UI.WebControls.Repeater MenuRepeater;
  protected ArrayList links = new ArrayList();

  private void Page_Load(object sender, System.EventArgs e) {
    MenuRepeater.DataSource = links;
    MenuRepeater.DataBind();
  }

  public ArrayList Links {
    get { return links; }
  }
}

В методе Page_Load устанавливается источник данных для элемента Repeater.

Рассмотрим далее, каким образом используется данный шаблон в пользовательском компоненте LeftMenuModule.ascx - общее для всех страниц сайта меню навигации.

LeftMenuModule.ascx

<%@ Control Language="c#" AutoEventWireup="false" 
  Codebehind="LeftMenuModule.ascx.cs"
  Inherits="GotDotNetTemplates.LeftMenuModule"
  TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<%@ Register TagPrefix="template"
  TagName="LeftMenuTemplate"
  Src="Templates/LeftMenuTemplate.ascx" %>
<template:LeftMenuTemplate id="LeftMenuTemplate" runat="server"></template:LeftMenuTemplate>

Видно, что использование шаблона меню в пользовательском компоненте аналогично использованию шаблона в aspx-странице. Следует отметить, что свойства шаблона меню задаются не декларативно как в случае с шаблоном страницы сайта, а программно - см. ниже.

LeftMenuModule.ascx.cs

public abstract class LeftMenuModule: System.Web.UI.UserControl {
  protected LeftMenuTemplate LeftMenuTemplate;

  private void Page_Load(object sender, System.EventArgs e) {
    LeftMenuTemplate.Links.Add(new LinkHelper(Request.ApplicationPath + 
		"/Default.aspx", "Главная страница"));
    LeftMenuTemplate.Links.Add(new LinkHelper(Request.ApplicationPath + 
		"/AddNewsItem.aspx", "Добавление новости"));
    LeftMenuTemplate.Links.Add(new LinkHelper(Request.ApplicationPath + 
		"/StaticPage.aspx", "Статическая страница"));
  }
}

В методе Page_Load заполняется список ссылок в шаблоне левого меню, в список добавляются объекты LinkHelper для каждого пункта меню. Программный способ установки свойств шаблона в методе Page_Load следует применять в случае свойств сложных типов данных, которые нельзя установить декларативно как в случае, например, простых строковых свойств.

Templates/LinkHelper.cs

  public class LinkHelper {
    private string url;
    private string title;

    public LinkHelper(string url, string title) {
      this.url = url;
      this.title= title;
    }

    public string Url	{
      get { return url; }
      set { url = value; }
    }

    public string Title {
      get { return title; }
      set { title = value; }
    }
}

Данный класс предназначен для хранения атрибутов ссылок левого меню - адреса и текста.

Рассмотрим, наконец, последнюю страницу сайта - страницу для вывода некоторой статической информации StaticPage.aspx.

StaticPage.aspx

<%@ Page language="c#" AutoEventWireup="false" %>
<%@ OutputCache Duration="3600" VaryByParam="None" %>
<%@ Register TagPrefix="template"
  TagName="DefaultTemplate"
  Src="Templates/DefaultTemplate.ascx" %>
<template:DefaultTemplate id="DefaultTemplate"
  runat="server"
  Title="GotDotNetTemplates - Статическая страница"
  LeftModuleUrl="~/LeftMenuModule.ascx"
  CenterModuleUrl="~/StaticPageCenterModule.ascx">
</template:DefaultTemplate>

Особенность данной страницы - использование директивы OutputCache, которая позволяет кэшировать страницу в течение длительного времени. Рассмотренная методика построения шаблонов позволяет применять кэширование, как на уровне страниц, так и на уровне отдельных блоков страницы - пользовательских компонентов. Разумное использование возможностей кэширования позволяет практически нивелировать накладные расходы, связанные с динамической сборкой страниц.

Заключение

Рассмотренная методика построения шаблонов страниц достаточно проста, универсальна и легко расширяема. В частности, ее несложно обобщить до уровня системы управления контентом, для этого достаточно хранить в базе данных информацию о шаблонах, их свойствах и значениях этих свойств для конкретных документов сайта. Потребуется одна страница-контроллер, которая будет формировать содержимое страницы по идентификатору документа, передаваемому в строке url. Можно придумать и другие варианты расширения, технология не накладывает практически никаких ограничений.

Приложение

Исходный код сайта.


Может пригодится:


Автор: rsivanov
Прочитано: 5785
Рейтинг:
Оценить: 1 2 3 4 5

Комментарии: (0)

Добавить комментарий
Ваше имя*:
Ваш email:
URL Вашего сайта:
Ваш комментарий*:
Код безопастности*:

Рассылка новостей
Рейтинги
© 2007, Программирование Исходники.Ру