Websites, such as Microsoft.com, use virtual directories to redirect visitors to featured site content. I maintain a website for an organization that had to comply with a federal law requiring the redirection of a virtual directory to a feature page about the law. This article is an extension of the How to Redirect Folder Requests with ASP.NET article by James H. Byrd that inspired my solution for compliance to the law for that website.

Key Technologies and Concepts

Loading XML data into a DataSet
Editing XML data with a DataSet
Sorting and Filtering with a DataView

This article describes how to use a web form in ASP.NET to manage data in XML files. The code snippets in this article demonstrate inserting, updating, and deleting row entries from an XML data file that has been loaded into the DataSet class using the ReadXML method. This article also demonstrates how to list the data from the XML file, and how to sort the records from the XML file based on fields in the content. This solution is not a substitute for database since the solution does not deal with collision updates from multiple users at the same time.

Sample XML File

For the examples in this article, I use the Redirection.xml from James' article. The example represents a table named Redirections with records called Redirection:

<? xml version="1.0" standalone="yes"?>
<Redirections>
  <Redirection RequestPath="/Home" Target="~/Default.aspx" />
  <Redirection RequestPath="/Config" Target="~/RedirectionFile.aspx" />
  <Redirection RequestPath="/Setup" Target="~/IISSetup.aspx" />
</Redirections>

You'll need the following namespaces in the C# code for execution:

using System.Collections.Generic;
using System.Data;

Reading XML into a DataSet

ASP.NET provides the DataSet class with methods that read and parse an XML file for access within code. The following code snippet illustrates the XMLRead and XMLWrite methods from the DataSet class:

DataSet mdsRedirect = new DataSet();
mdsRedirect.ReadXml(HttpContext.Current.Server.MapPath(
  "~/App_Data/Redirection.xml"));
mdsRedirect.WriteXml(HttpContext.Current.Server.MapPath(
  "~/App_Data/Redirection.xml"));

The DataSet class contains an array of rows, each row called Redirection with two columns called RequestPath and Target.

Inserting Data

The following code sample shows how to insert a new row into the DataSet:

DataSet mdsRedirect = new DataSet();
mdsRedirect.ReadXml(
  HttpContext.Current.Server.MapPath("~/App_Data/Redirection.xml"));
DataRow xRow = mdsRedirect.Tables[0].NewRow();
xRow["RequestPath"] = "/Login";
xRow["Target"] = "%/login.aspx";
mdsRedirect.Tables[0].Rows.Add(xRow);
mdsRedirect.WriteXml(
  HttpContext.Current.Server.MapPath("~/App_Data/Redirection.xml"));
 
(Note: The new row will be appended at the end of the array of rows.)

Updating Data

To update a row in the DataSet, you must locate the row and update the fields within the row. A key field must be selected and searched, using the value of the field prior to the change, to locate the correct row for update. For this example the "RequestPath" field is used as the key field. If the virtual directory "/Login" should have been "/Logon" and the target associated should have pointed to "%/logon.aspx", here is an example of how you could change it:

DataSet mdsRedirect = new DataSet();
mdsRedirect.ReadXml(
  HttpContext.Current.Server.MapPath("~/App_Data/Redirection.xml"));
 
string strkey = "/Login";
foreach (DataRow xRow in mdsRedirect.Tables[0].Rows)
{
  string strcompare = Convert.ToString(xRow["RequestPath"]);
  if (strkey == strcompare)
  {
    xRow["RequestPath"] = "/Logon";
    xRow["Target"] = "%/Logon.aspx";
    break;
  }
}
mdsRedirect.WriteXml(
  HttpContext.Current.Server.MapPath("~/App_Data/Redirection.xml"));

Deleting Data

To delete the "/Config" virtual directory, a key field must be selected and searched, using the value of the field prior to the delete, to locate the correct row for removal. For this example the "RequestPath" field is used again as the key field. Use the following code:

DataSet mdsRedirect = new DataSet();
mdsRedirect.ReadXml(
  HttpContext.Current.Server.MapPath("~/App_Data/Redirection.xml"));
 
foreach (DataRow xRow in mdsRedirect.Tables[0].Rows)
{
  string strRequestPath = Convert.ToString(xRow["RequestPath"]).ToLower();
  if ("/Config" == strRequestPath)
  {
    xRow.Delete();
    break;
  }
}
mdsRedirect.WriteXml(
  HttpContext.Current.Server.MapPath("~/App_Data/Redirection.xml"));

Listing Data

If you want to list the contents of the DataSet in the same order as the XML file, use the following code:

DataSet mdsRedirect = new DataSet();
mdsRedirect.ReadXml(
  HttpContext.Current.Server.MapPath("~/App_Data/Redirection.xml"));
 
foreach (DataRow xRow in mdsRedirect.Tables[0].Rows)
{
  string strRequestPath = Convert.ToString(xRow["RequestPath"]).ToLower();
  string strTarget = Convert.ToString(xRow["Target"]);
  // Insert your formatting code here
}

Sorting Data

Once the list has grown to some size it will become harder for users to find content if the list is not sorted. Extending the DataSet object with the DataView class enables sorting and filtering. The code example below shows a pass at the information sorted by RequestPath:

DataSet mdsRedirect = new DataSet();
mdsRedirect.ReadXml(
  HttpContext.Current.Server.MapPath("~/App_Data/Redirection.xml"));
DataView sdv = mdsRedirect.Tables[0].DefaultView;
sdv.Sort = "RequestPath";
foreach (DataRowView xRow in sdv)
{
  string strRequestPath = Convert.ToString(xRow["RequestPath"]).ToLower();
  string strTarget = Convert.ToString(xRow["Target"]);
  // Insert your formatting code here
}

I have seen many blogs on the internet complaining that sort doesn't work with the DataSet class. I had the same problem until I discovered the combination DataSet and DataView classes. Please note the use of a different Row class between the unsorted DataSet example and the sorted DataView class example. While my working example did not need complex sorting, it is possible to make a complex sort with multiple fields using syntax similar to SQL ORDER BY statements. In the example code below, I specify a primary sort on RequestPath in descending order and a secondary sort on Target in ascending order:

DataSet mdsRedirect = new DataSet();
mdsRedirect.ReadXml(
  HttpContext.Current.Server.MapPath("~/App_Data/Redirection.xml"));
DataView sdv = mdsRedirect.Tables[0].DefaultView;
sdv.Sort = "RequestPath DESC, Target ASC";
foreach (DataRowView xRow in sdv)
{
  string strRequestPath = Convert.ToString(xRow["RequestPath"]).ToLower();
  string strTarget = Convert.ToString(xRow["Target"]);
  // Insert your formatting code here
}

Filtering Data

The DataView class may also be used to filter rows. The following example shows how to select all rows except where "RequestPath" has the value of "/config:"

DataSet mdsRedirect = new DataSet();
mdsRedirect.ReadXml(
  HttpContext.Current.Server.MapPath("~/App_Data/Redirection.xml"));
DataView sdv = mdsRedirect.Tables[0].DefaultView;
sdv.RowFilter = "RequestPath = ‘/config'";
foreach (DataRowView xRow in sdv)
{
  string strRequestPath = Convert.ToString(xRow["RequestPath"]).ToLower();
  string strTarget = Convert.ToString(xRow["Target"]);
  // Insert your formatting code here
}

The RowFilter member of the DataView class is a powerful parameter that can be set with complex rules. There are many blogs on the internet that go into detail so I will not attempt to explain all of its capabilities here.

Download the Code

To download the sample code for this article, right-click over the link below and select the appropriate "Save As" option on the popup menu. The exact wording of this option differs a little from browser to browser.

The zip file contains a fully-functional Visual Studio 2008 project.

Download the Demo Project

The sample project includes a web form called ManageRedirection.aspx (with ManageRedirection.aspx.cs). You may use this example in your projects. This form actually consist of three internal forms, divmanageform (list and delete), divinsertform (insert), and divedit (update), which are shown or not shown by setting the Visible attribute of the div tag to a true or false value. Since the value is set dynamically in the ".CS" file, these div tags must have the attribute runat="server" in the ".ASPX" file.

The example ".CS" file has code commented out near the top of the page so the script will run standalone. The code can be used for security integration with the Membership class. This unused code will check for the roles assigned to an authenticated user. If an authenticated user does not have the role assigned for access to this page, the page redirects to the default.aspx file in the same directory.

Conclusion

This article has demonstrated using the DataSet and DataView classes to maintain an XML file.

  • Populate DataSet Class from an XML file.
  • Write the contents of DataSet Class to an XML file.
  • Insert a row or record into a DataSet Class.
  • Update a row or record in a DataSet Class.
  • Delete a row or record in a DataSet Class.
  • Combine DataSet and DataView Classes to sort and filter the contents of an XML file.

Please see the Download the Code side bar for instructions if you'd like to download the demo project presented in this article.