Web applications are dynamic - many requiring unique content and interfaces for each user. There are a myriad of ways to take user content out of a database and present it in a browser. This article focuses on the different ways it can be done in the Microsoft world (specifically in ASP.NET), why we chose XSLT for our own product, and finally, a look at our technical implementation.
Planning for Dynamic Content
Whether you are in the process of building a new business web application or planning to build one, you most likely need to address how your web application will handle displaying different content for different users.
When considering the different options for displaying dynamic content, you generally need to take into account the following aspects:
Usability might be one of the most critical aspects in the success (or lack thereof) of your application.
- Development Time
This includes the total amount of development time involved in satisfying your current application requirements.
Regardless of how comprehensive your current requirements are, applications tend to evolve over time. It’s important to evaluate the development effort and skill sets required to accommodate changes.
- Support, Maintenance, and Ongoing Enhancements
Commonly ignored by many when planning new development projects, it is generally responsible for a good chunk of the total cost of an application over the span of its life. This includes bug fixes, client customizations, minor application enhancements, and of course, QA and testing.
The Options in ASP.NET
Generally, web applications that use ASP.NET have two main options for displaying dynamic content:
- Server Controls
- With Binding – retrieving the relevant data and binding it to the appropriate ASP.NET server controls on a web form.
- In Code – populating the appropriate ASP.NET server controls in code.
- In Code – constructing the HTML to display in code based on the information retrieved from the database.
- With XSLT – retrieving the database information in XML format and then transforming it into HTML with XSLT.
A third option is Silverlight, a new technology introduced as an option for web applications by Microsoft about a year ago. Silverlight provides a very rich GUI, with the power of the .NET platform (a subset, actually) and tools that make web application development similar to the XAML interfaces found in the latest Windows application development tools. Silverlight is outside the scope of this particular article though.
Real-World Use Case: Scopings
When we started evaluating the requirements for Scopings, our homegrown recruiting platform, we needed a way to present complex content with a unique look and feel, a high level of usability, an infrastructure that can easily adapt to frequent and substantial changes, and built-in capabilities for globalization.
Very quickly, we realized that although we could use ASP.NET server controls to build the first revision of Scopings in a relatively short period of time, this wouldn’t adapt well to the frequent changes we expected to be an inevitable part of the product lifecycle. This option would substantially increase our total cost of ownership.
After much analysis and many discussions, it became clear to us that designing our own infrastructure for constructing HTML using XML and XSLT would satisfy all of our requirements. We sat down and started to design an infrastructure that has ultimately been used for more than 80% of the functionality on Scopings.
Constructing the HTML
The idea behind the Scopings infrastructure was to allow us to make substantial changes to our user interface, while eliminating the need for any code changes and development staff involvement, and substantially decreasing the amount of QA required following any changes to the user interface.
To accommodate these requirements, the Scopings infrastructure was built to be completely indifferent to the information retrieved from our database and to the way the information is ultimately displayed.
To achieve this, we designed the infrastructure as follows:
- A separate Stored Procedure was built against each web content page to be displayed, and was designed to only return XML back to the calling code.
- Upon loading a web page, the code-behind would load the XML for the current user. The XSLT would then transform the XML to an HTML interface for the user.
- All styling is handled with CSS.
Given the above mechanism, any change to the way we display data, or to the content of the page, would only involve the following:
- If any additional data is needed, we would modify the Stored Procedure to include the new data required. If no additional data is needed, no change to the Stored Procedure will be made.
- Modify the XSLT to include any new data to be displayed, and any changes to the display.
- Modify the corresponding CSS files to make any changes required for styling.
- Test display changes and specific page functionality, if any.
This allows for content and interface changes that require little to no development efforts, and can be done very quickly with minimal testing.
Constructing Web Interfaces with XSLT
In this section, I’m going to provide the technical details needed to build a simple infrastructure for retrieving dynamic content from a SQL Server database and displaying it on a web page using XSLT.
As discussed above, the process of displaying dynamic content includes the following steps:
- Extracting Database Content – building a Stored Procedure to output all web page content as XML.
- Retrieving the XML from the Database – building a function to call the Stored Procedure and retrieve its data.
- Transforming XML into HTML using XSLT – developing the XSLT required to transform the XML retrieved from the database into HTML.
- Displaying Content on the Web Page – configuring the web page to retrieve the XML, convert it to HTML, and finally display the interface to the user.
Step 1 - Extracting Database Content
The most flexible and powerful way to extract database content is simply to create Stored Procedures that output XML. This way, all the data needed for the interface can be easily extracted with one database call. A future change to the content only requires slight adjustments of the appropriate Stored Procedure without any changes to the calling code.
The following is a sample Stored Procedure that builds an XML document with a specific user’s first and last name, and a list of tasks this particular user needs to accomplish:
CREATE procedure [dbo].[Get_User_Profile_XML]
SET NOCOUNT ON;
SELECT Users.[User_ID] AS [@id],
Users.First_Name AS [@first],
Users.Last_Name AS [@last],
SELECT Tasks_ID AS [@id],
Task_Description AS [@description]
WHERE Users_Tasks.[User_ID] = Users.[User_ID]
FOR XML PATH('task'),TYPE, ROOT('tasks')
WHERE Users.[User_ID] = @User_ID
FOR XML PATH('user'), TYPE;
Note: This was written against SQL Server 2005, and can be easily adjusted to use
FOR XML EXPLICIT for use with SQL Server 2000.
The output XML of the above Stored Procedure might look as follows:
<user id="U12" first="John" last="Smith">
<task id="T34" description="Annual review"/>
<task id="T56" description="File my taxes"/>
Step 2 – Retrieving the XML Content from the Database
After building the appropriate Stored Procedure, we need to develop the code that can call this procedure on runtime and extract the appropriate data for the current user.
As increasing flexibility and lowering long-term maintenance costs are our primary goals, it is often best to keep the code needed to retrieve that database information almost entirely indifferent of the content it gets back. Extracting XML directly from the Stored Procedure gives us just that. We can keep changing the XML structure and content without requiring any changes to the calling code.
The following function might be used to extract the XML data from the Stored Procedure above and send the XML (as a string) back to the client:
private string GetUserProfileXML(string userId)
const string MY_CONNECTION_STRING = "YOUR CONNECTION STRING";
const string PROCEDURE = "dbo.Get_User_Profile_XML";
using (SqlConnection connection = new SqlConnection(MY_CONNECTION_STRING))
using (SqlCommand command = new SqlCommand())
command.Connection = connection;
command.CommandText = PROCEDURE;
command.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("@User_ID", SqlDbType.VarChar, 10);
param.Value = new SqlString(userId);
using (XmlReader reader = command.ExecuteXmlReader())
string resultXml = reader.ReadOuterXml();
Note: This opens a connection to SQL Server, configures the command object and its @ID parameter, and reads the XML as a string from the
Step 3 –Transforming XML into HTML using XSLT
Our next task is to transform the XML into HTML that can be displayed to the current user.
XSLT can be quite handy and an ideal solution when it comes to transforming XML into HTML. XSLT offers enormous flexibility, as it can be quickly adjusted to handle any changes to the XML content or changes to new requirements.
XSLT files can be easily included as part of any web application, and although this is beyond the scope of this article, development teams can choose to slightly adjust this approach and globalize their web applications by developing different XSLT files per language supported.
The following XSLT might be used to process the XML data above:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:value-of select="concat('Tasks for ', @first,' ',@last,':')"/>
Note: This outputs the heading for the page (first and last name), and then outputs every associated user task.
The HTML result might look like the following:
<div class="userInfo">John Smith Tasks</div>
<div class="userTask"><a href="taskinfo.aspx?id=T34">Annual review</a></div>
<div class="userTask"><a href="taskinfo.aspx?id=T56">File my taxes</a></div>
Step 4 – Displaying Content on the Web Page
The final step is to create the web page needed to process and display the appropriate user content. As described at the beginning of the article, we need to retrieve the XML from the database by calling the "
GetUserProfileXML" function we developed earlier, transforming the XML into HTML using the XSLT file above, and then finally displaying the HTML to the user.
We first create an ASPX page with a server side
DIV to ultimately contain the HTML. The page might look like the following:
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="userprofile.aspx.cs" Inherits="UserProfile" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml" >
<title>My User Profile Page</title>
<form id="form1" runat="server">
<div id="_divData" runat="server">
DIV is set to run on the server so the HTML can be assigned on the server.
Next, we need to develop the function that takes the XML and transforms it into HTML using an XSLT file.
A function that accepts an XSLT file name and the XML data, and performs the transformation, might look like the following:
private string GetPageHTML(string xsltFileName,string xmlData)
string fullXsltFilePath = Server.MapPath("~/" + xsltFileName);
using (XmlReader dataReader = LoadXMLToReader(xmlData))
XslCompiledTransform xslTrans = new XslCompiledTransform();
using (MemoryStream outputStream = new MemoryStream())
xslTrans.Transform(dataReader, null, outputStream);
outputStream.Position = 0;
using (StreamReader sr =
new StreamReader(outputStream, Encoding.UTF8))
string resultHtml = sr.ReadToEnd();
Note: This function gets the full path to the XSLT file, loads the XML data into an
XmlReader, and then uses an
XslCompiledTransform object to transform the XML into HTML and return the HTML as string to the calling code. Also,
XslCompiledTransform is a thread-safe object, so I would highly recommend caching it to further increase website performance.
Finally, to wrap everything up, here is what the
Page_Load function on the web page might look like:
protected void Page_Load(object sender, EventArgs e)
const string XSLT_FILE_NAME = "UserProfile.xslt";
string userId = "U12";
string xmlData = GetUserProfileXML(userId);
string html = GetPageHTML(XSLT_FILE_NAME, xmlData);
_divData.InnerHtml = html;
Note: The User ID is hard-coded, but it should be retrieved dynamically based on the current logged-in user.
Dynamic content for web applications can be produced in several ways, but if you are looking to build a web application with great flexibility, a high level of usability, and low total cost of ownership, using XSLT to transform XML into an HTML interface might be the right approach.