Calling a ASP.NET Method Using jQuery

Over the last few months I have had the ability to mess around with a bit of jQuery. Even though I don’t have the complete understanding on how it works, I can see the benefits of writing my code in jQuery compared to bashing out lots of lines of JavaScript to do the same thing.

One the cool features I have used is calling one of my .NET methods using the “$.ajax” jQuery command. In my example (below), I have created two aspx pages. The code-behind of my first page  (jQueryMethodTest.aspx) will only contain a public static method called “WhatIsYourName”, which returns a string value.

public static string WhatIsYourName(string name)
    if (!String.IsNullOrEmpty(name))
        return String.Concat("Hello ", name, "!");
        return String.Empty;

Remember, the jQueryMethodTest.aspx page only needs to contain our method nothing else! Additional methods can be added. Just don’t add any web controls.

The second page (jQueryAjax.aspx), will contain our jQuery code and some HTML to output our result from calling the “WhatIsYourName” method.

<html xmlns="">
<head runat="server">
    <script type="text/javascript" language="javascript" src="javascript/jquery.js"></script>
<script type="text/javascript">
    $(document).ready(function() {
        $("#btnSubmitName").click(function(event) {
                type: "POST",
                url: "jQueryMethodTest.aspx/WhatIsYourName",
                data: "{'name': '" + $('#name').val() + "'}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function(message) {
                error: NameFailed

    function ShowPopup(result) {
        if (result.d != "") {
        else {
            $("#Message").html("I didn't get your name.");

    function NameFailed(result) {
        $("#Message").html(result.status + ' ' + result.statusText);

    <form id="form1" runat="server">
        <input id="name" name="name" type="text" />
        <br />
        <input id="btnSubmitName" name="btnSubmitName" type="button" value="Submit" />
        <br /><br />
        <span id="Message" style="color:Red;"></span>

If all goes well, you should get the following result:

Calling ASP Method Using jQuery

The “$.ajax” jQuery command requires the following parameters in order to work:

  • url – links to where our .NET method is placed.
  • data – retrieves the value from some control in our page to pass to our method. Remember, the name of the parameter must be named the same as the parameter from our .NET method.
  • dataType – the response type.
  • contentType – the request content type.
  • success – the JavaScript function that gets fired on postback.
  • error – the Javascript function that gets fired if there is a failure. This is an optional parameter.

I guess jQuery’s motto really is true: “write less, do more”.

Dynamically Load ASP.NET UserControls

I had created some .NET UserControl’s that I needed to dynamically add to a Panel control within my page. I previously thought generating my UserControl’s dynamically would be the same as dynamically generating any other .NET Control, like this:

private void CreateControls()
    //Create control
    TextBox txtUser = new TextBox();
    txtUser.ID = "txtUser";
    txtUser.Text = "Please enter a value";
    //Add Control to Panel already in our .NET page

But I was wrong! :-)

Fortunately, there is a really easy way to to add a UserControl dynamically by simply making use of the “LoadControl” method. The “LoadControl” method takes a single parameter containing the virtual path of your UserControl. For example:

private void CreateControls()
    //Create control
    Control myUserControl = LoadControl("MyUserControl.ascx") as MyUserControl;
    myUserControl.ID = "ucMyControl";
    //Add Control to Panel already in our .NET page


Use YouTubes RSS Feed To Output A List of Videos

Ok! I admit it! I posted some incorrect information from one of my previous blog posts to “Dynamically Output A List of YouTube Video’s In ASP.NET”. I stupidly said: “The RSS feed is not structured in a nice enough format to output all the information you may need with ease.” I must have been drunk when I wrote that. As you can see from a sample of their RSS feed below I was wrong:

    <category scheme='' term='bike'/>
    <category scheme='' term='Podcast'/>
    <category scheme='' term='Pedrosa'/>
    <category scheme='' term='motorcycles'/>
    <category scheme='' term='Honda+RC212V'/>
    <category scheme='' term='speed'/>
    <category scheme='' term='Suzuki+GSV-R800'/>
    <category scheme='' term=''/>
    <category scheme='' term='Sports' label='Sport'/>
    <category scheme='' term='Rossi'/>
    <category scheme='' term='motorcycle+road+racing'/>
    <category scheme='' term='motograndprix'/>
    <category scheme='' term='Yamaha+YZR+M1'/>
    <category scheme='' term='Mugello'/>
    <category scheme='' term='Italy'/>
    <category scheme='' term='Stoner'/>
    <category scheme='' term='Ducati+Desmosedici+GP8'/>
    <category scheme='' term='MotoGP'/>
    <category scheme='' term='Lorenzo'/>
    <title type='text'>MotoGP action from Mugello 2009</title>
    <content type='text'>The best of the action from the Gran Premio D&amp;#180;Italia Alice, the fifth round of the 2009 motogp World Championship.</content>
    <link rel='alternate' type='text/html' href=''/>
    <link rel='' type='application/atom+xml' href=''/>
    <link rel='' type='application/atom+xml' href=''/>
    <link rel='self' type='application/atom+xml' href=''/>
      <gd:feedLink href='' countHint='24'/>
      <media:category label='Sport' scheme=''>Sports</media:category>
      <media:description type='plain'>The best of the action from the Gran Premio D&amp;#180;Italia Alice, the fifth round of the 2009 motogp World Championship.</media:description>
      <media:keywords>MotoGP, Italy, Mugello, Podcast, Stoner, Pedrosa, Rossi, Lorenzo, Yamaha+YZR+M1, Ducati+Desmosedici+GP8, Honda+RC212V, Suzuki+GSV-R800, motorcycle+road+racing, motograndprix, motorcycles, bike, speed</media:keywords>
      <media:player url=''/>
      <media:thumbnail url='' height='90' width='120' time='00:00:38.500'/>
      <media:thumbnail url='' height='90' width='120' time='00:00:19.250'/>
      <media:thumbnail url='' height='90' width='120' time='00:00:57.750'/>
      <media:thumbnail url='' height='240' width='320' time='00:00:38.500'/>
      <media:title type='plain'>MotoGP action from Mugello 2009</media:title>
      <yt:duration seconds='77'/>
    <gd:rating average='4.862069' max='5' min='1' numRaters='29' rel=''/>
    <yt:statistics favoriteCount='10' viewCount='1055'/>

Each “entry” element within the RSS feed represents a YouTube video. You are able to extrapolate all the important information about each movie such as Average Score, View Count, Thumbnail Images, Video Description, etc. Really useful stuff!

You may be thinking: Why should I use an RSS feed to retrieve the video information rather than using the YouTube API? Well, using a YouTube API is definitely the easier and most straight-forward method. But what you should be aware that the API only works from .NET 2.0 onwards. There isn’t a YouTube API for .NET 1.1. Unfortunately, I only found this out when I tried to implement the API into one of my .NET 1.1 client sites.

The code I have written below, reads the YouTube RSS feed and stores the information in a DataTable.

private void GetYouTubeData(string YouTubeUrl)
    //Create DataTable to store specific YouTube information
    DataTable dtYouTubeVideoData = new DataTable();

    DataRow drYouTubeVideoData;

    //Link to YouTube RSS feed
    XmlTextReader rssReader = new XmlTextReader(YouTubeUrl);
    XmlDocument xmlDoc = new XmlDocument();

    //Download the XML (via the XmlTextReader)

    //Select all nodes starting with "entry"
    XmlNodeList xmlNodeList = xmlDoc.GetElementsByTagName("entry");
    //For each "entry" element found
    foreach (XmlNode node in xmlNodeList)
        drYouTubeVideoData = dtYouTubeVideoData.NewRow();

        //Create a new document, to search through the inner contents
        XmlDocument innerXmlDocument = new XmlDocument();

        // Get movie ID
        drYouTubeVideoData["YouTubeID"] = innerXmlDocument.GetElementsByTagName("id")[0].InnerText.Replace("", "");

        // Get movie title
        drYouTubeVideoData["Title"] = innerXmlDocument.GetElementsByTagName("title")[0].InnerText;

        //Get movie description
        drYouTubeVideoData["Description"] = innerXmlDocument.GetElementsByTagName("content")[0].InnerText;
        //Get the thumbnails
        XmlNodeList mediaTumbnail = innerXmlDocument.GetElementsByTagName("media:thumbnail");

        //Iterate through each thumbnail and only get one thumbnail per <entry>.
        foreach (XmlNode thumbnailNode in mediaTumbnail)
            if (thumbnailNode.Attributes["height"].Value == "90" && thumbnailNode.Attributes["url"].Value.EndsWith("1.jpg"))
                drYouTubeVideoData["ImageUrl"] = thumbnailNode.Attributes["url"].Value;

        //Get movie rating
        XmlNodeList ratings = innerXmlDocument.GetElementsByTagName("gd:rating");

        foreach (XmlNode ratingsNode in ratings)
            drYouTubeVideoData["AverageRatings"] = ratingsNode.Attributes["average"].Value;

        //Get Statistics
        XmlNodeList statistics = innerXmlDocument.GetElementsByTagName("yt:statistics");

        foreach (XmlNode statisticsNode in statistics)
            drYouTubeVideoData["ViewCount"] = statisticsNode.Attributes["viewCount"].Value;



    //Bind YouTube data to repeater
    repVideoList.DataSource = dtYouTubeVideoData;

Dynamically Output A List of YouTube Videos In ASP.NET

I recently needed to dynamically display a list of YouTube video’s from a specific YouTube account. If you plan to output the list of video’s straight from the YouTube’s RSS feed into your .NET application don’t bother. The RSS feed is not structured in a nice enough format to output all the information you may need with ease. For example, video ratings, time, etc are all in the same XML block.

As you can see from the screenshot below, the ASP.NET page I created outputs all the information that you will probably want to show (if it doesn’t then it should give you a good starting point).


Before creating your own custom YouTube .NET application you will need to carry out two things:

  1. Go to the YouTube API Toolswebsite and download the “Google Data API SDK”. Once you have installed this on your computer. You will need to copy three dll’s from one of the sample projects:

    • Google.GData.Client.dll
    • Google.GData.Extensions.dll
    • Google.GData.YouTube.dll

    These dll's can be copied to your new project.

  2. Register a Developer Key. This is important! Without the developer key, your custom YouTube application will not work.

To create the page (above), copy the following code:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using Google.GData.Client;
using Google.GData.Extensions;
using Google.GData.Extensions.MediaRss;
using Google.YouTube;
using Google.GData.YouTube;
using System.Text;
using System.Data;

public partial class _Default : System.Web.UI.Page
    private string YouTubeChampionshipChannel;
    private string YouTubeClientID;
    private string YouTubeDeveloperKey;
    public string YouTubeMovieID;
    public DataTable dtVideoData = new DataTable();

    protected void Page_Load(object sender, EventArgs e)
        //Pass User Name to the YouTube link
        YouTubeChampionshipChannel = "MotoGP";

        //Add the YouTube Developer keys.
        //Register a Developer Key at:
        YouTubeClientID = "test";
        YouTubeDeveloperKey = "testabc123";


        //Assign the first video details on page load.
        if (String.IsNullOrEmpty(YouTubeMovieID))
            YouTubeMovieID = dtVideoData.Rows[0]["VideoID"].ToString();
            lblDescription.Text = dtVideoData.Rows[0]["Description"].ToString();


    private void CreateVideoFeed()
        YouTubeRequestSettings settings = new YouTubeRequestSettings("MotoGP Channel", YouTubeClientID, YouTubeDeveloperKey);
        YouTubeRequest request = new YouTubeRequest(settings);

        //Link to the feed we wish to read from
        string feedUrl = String.Format("{0}/uploads?orderby=published", YouTubeChampionshipChannel); ;

        DataRow drVideoData;

        Feed<Video> videoFeed = request.Get<Video>(new Uri(feedUrl));

        //Iterate through each video entry and store details in DataTable
        foreach (Video videoEntry in videoFeed.Entries)
            drVideoData = dtVideoData.NewRow();

            drVideoData["Title"] = videoEntry.Title;
            drVideoData["Description"] = videoEntry.Description;
            drVideoData["DateUploaded"] = videoEntry.Updated.ToShortDateString();
            drVideoData["Ratings"] = videoEntry.YouTubeEntry.Rating.Average.ToString();
            drVideoData["NoOfComments"] = videoEntry.CommmentCount.ToString();
            drVideoData["VideoID"] = videoEntry.YouTubeEntry.VideoId;
            drVideoData["Duration"] = videoEntry.YouTubeEntry.Duration.Seconds.ToString();


        repVideoList.DataSource = dtVideoData;

    protected void repVideoList_ItemDataBound(object sender, RepeaterItemEventArgs e)
        if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            DataRowView drVideo = (DataRowView)e.Item.DataItem;

            LinkButton showVideo = (LinkButton)e.Item.FindControl("btnShowVideo");
            Literal title = (Literal)e.Item.FindControl("Title");
            Literal description = (Literal)e.Item.FindControl("Description");
            Literal ratings = (Literal)e.Item.FindControl("Ratings");
            Literal noOfComments = (Literal)e.Item.FindControl("NoOfComments");
            Literal duration = (Literal)e.Item.FindControl("Duration");

            showVideo.CommandArgument = drVideo["VideoID"].ToString();
            title.Text = drVideo["Title"].ToString();
            description.Text = drVideo["Description"].ToString();
            ratings.Text = drVideo["Ratings"].ToString();
            noOfComments.Text = drVideo["NoOfComments"].ToString();
            duration.Text = drVideo["Duration"].ToString();

    protected void repVideoList_ItemCommand(object source, RepeaterCommandEventArgs e)
        // Pass the YouTube movie ID to flash
        YouTubeMovieID = e.CommandArgument.ToString();

        if (YouTubeMovieID == e.CommandArgument.ToString())
            lblDescription.Text = ((Literal)e.Item.FindControl("Description")).Text;



<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">
<html xmlns="">
<head runat="server">
    <form id="form1" runat="server">
    <div style="margin: 10px;">
        <div style="float: left; width: 300px; height: 400px; overflow: scroll;">
            <asp:Repeater ID="repVideoList" runat="server" OnItemDataBound="repVideoList_ItemDataBound"
                            <asp:LinkButton ID="btnShowVideo" runat="server">Show Video</asp:LinkButton>
                                <asp:Literal ID="Title" runat="server"></asp:Literal></strong>
                            <br />
                            <asp:Literal ID="Description" runat="server"></asp:Literal>
                            <br />
                            Rating: <asp:Literal ID="Ratings" runat="server"></asp:Literal>
                            <br />
                            Comments: <asp:Literal ID="NoOfComments" runat="server"></asp:Literal>
                            <br />
                            Duration: <asp:Literal ID="Duration" runat="server"></asp:Literal>
                            <br />
                            <br />
        <div style="float: left; margin-left: 15px;width:600px;2">
            <object width="480" height="385" style="float: left; clear: both; margin-bottom: 10px;">
                <param name="movie" value="<%=YouTubeMovieID %>&hl=en&fs=1&rel=0">
                <param name="allowFullScreen" value="true"></param>
                <param name="allowscriptaccess" value="always"></param>
                <embed src="<%=YouTubeMovieID %>&hl=en&fs=1&rel=0" type="application/x-shockwave-flash"
                    allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed>
            <div style="float: left;">
                <asp:Label ID="lblDescription" runat="server"></asp:Label>

This is just the beginning on what the YouTube API has to offer. For more information, visit the YouTube API website (

* Post Updated 18/06/2009 – You can output YouTube video’s via RSS feed *

ASP.NET Membership Provider - Validating Duplicate Email Addresses

ASP.NET Membership Provider makes implementing secure authenticating membership forms more straightforward. The ASP.NET Membership Provider contains so many useful methods. But I could not find a method within the Membership class to check whether there was an existing email address in the database even though you can state in the web.config (requiresUniqueEmail) file:

      type="System.Web.Security.SqlMembershipProvider, ..."

I created the following CustomValidator with a ServerValidate event to carry out the duplicate email check:

protected void DuplicateEmailCheck_ServerValidate(object source, ServerValidateEventArgs args)
        //Create MembershipUserCollection to collate a list of duplicate email addresses
        MembershipUserCollection memCollection = Membership.GetUserNameByEmail(args.Value.ToString());

        //If duplicate email addresses are found then error
        if (memCollection.Count > 0)
            args.IsValid = false;
            args.IsValid = true;

Validation To Check Length Of String Using Regular Expression

I came across a problem today when trying to find an effective way to validate the length of a password field within a registration form I was creating. ASP.NET already has a bunch of useful validation controls. Most of which I have already have in use within my registration form, such as the RequiredFieldValidator, CompareValidator and RangeValidator.

Now you might be thinking. What’s your problem dude? Its not hard to validate the length of a field. Yeah, you are right. But all the validation controls I am using (above) do not create post backs. I could have easily created a CustomValidator control to solve my problem, but this only fires once a post back has occurred.

I guess my only solution is to use a RegularExpressionVaildator which meant I had to do some research into RegEx. To use RegEx to validate the length of a string between 0 and y (some number), use the following expression:


To validate the exact length, use the following expression:


Both example’s above will accept any type of characters entered in the field.

What's The Difference Between NULL and DBNull

I always used NULL and DBNULL interchangeably in my coding around my database results without ever considering what were the differences. Fortunately, I stumbled upon a great blog written by Bilal Haidar, "Difference between NULL and DBNull"

If I understand correctly, you use DBNULL to check if a certain field in a database is null and you would use NULL to check if a whole record is not found in the database.

Outputting Custom Made Charts To An ASP.NET Page

A few weeks ago I was trying to implement a Bar and Pie Chart for a report in a web application. I found that most of the charting solutions on the web cost an arm and a leg. So I decided to have a bash at creating my own one.

I have been reading through the MCTS Application Development Foundation book and found a couple of chapters on using System.Drawing namespace to output graphics and create Pie Charts in a C# application. Great stuff! However, I encountered a problem when my Chart was rendered within a web page that contains other HTML content. For some reason there was no HTML in my page and all that was displayed was my Chart.

This is how I wanted my chart to be inserted into my page:


However, when my charting code was added, my page looked like this:


After investigating this problem further it seems that when you output the chart image to a stream the whole page is rendered as an image which removes all the HTML. For example:

Response.ContentTye = "image/gif"; //MIME type
Bitmap.Save(Response.OutputStream, ImageFormat.Gif);

In order to get around this problem required quite a strange work around:

  1. In the page where you need to the chart to be displayed (we will call Report.aspx) add an ASP Image control that will link to an .aspx page that will contain your chart. Things will become more clearer in the next step.
<asp:Image ID="imgSelfAverageBarChart" ImageUrl="/Charts/BarChart.aspx" runat="server" />
  1. Create a new ASP.NET page that will contain all the code for your chart (we will call BarChart.aspx). Now you might be thinking how can I send the figures to the chart? Well this can be done be using Session variables or parameters within the web page link that you used in your ImageUrl in the Report.aspx page.
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
public partial class BarChart : System.Web.UI.Page
    protected void Page_Load(object sender, EventArgs e)
            List<string> Questions = new List<string>();
            List<float> Values = new List<float>();
            //Check the session values have values
            if (Session["Sections"] != null && Session["SelfAverageValue"] != null)
                Questions = (List<string>)Session["Sections"];
                Values = (List<float>)Session["SelfAverageValue"];
            Bitmap imageBitmap = new Bitmap(600, 285);
            Graphics g = Graphics.FromImage(imageBitmap);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            Brush[] brushes = new Brush[5];
            brushes[0] = new SolidBrush(Color.FromArgb(255, 216, 0));
            brushes[1] = new SolidBrush(Color.FromArgb(210, 219, 252));
            brushes[2] = new SolidBrush(Color.FromArgb(0, 127, 70));
            brushes[3] = new SolidBrush(Color.FromArgb(0, 148, 255));
            brushes[4] = new SolidBrush(Color.FromArgb(190, 99, 255));
            int xInterval = 70;
            int width = 60;
            float height = 0;
            //Draw the Pie Chart
            for (int i = 0; i < Values.Count; i++)
                height = (Values[i] * 40);        // adjust barchart to height of Bitmap
                //Draws the bar chart using specific colours
                g.FillRectangle(brushes[i], xInterval * i + 50, 260 - height, width, height);
                //Draw legend
                g.FillRectangle(brushes[i], 420, 25 + (i * 50), 25, 25);
                g.DrawString(Questions[i], new Font("Arial", 8, FontStyle.Bold), Brushes.Black, 450, 31 + (i * 50));
                // Draw the scale
                g.DrawString(Convert.ToString(Math.Round(Convert.ToDecimal(Values[i]), 2)), 
                new Font("Arial", 10, FontStyle.Bold), Brushes.Black, xInterval * i + 45 + (width / 3), 300 - height);
                // Draw the axes
                g.DrawLine(Pens.Black, 40, 10, 40, 260);        //   y-axis
                g.DrawLine(Pens.Black, 20, 260, 400, 260);       //  x-axis
            Response.ContentType = "image/gif";
            imageBitmap.Save(Response.OutputStream, ImageFormat.Gif);
  1. Go back to Report.aspx page and add the code to parse your values in a Session.
//Some code that carried out calculations
//Calculated the averages
float selfAverageTotal = selfAssessValue / numberOfSections;
float otherAverageTotal = otherAssessValue / numberOfSections;
//Add generic list
List<string> questions = new List<string>(); //To store the names of x and y axis
List<float> averages = new List<float>();    //To store the values
questions.Add("Self Average Total");
questions.Add("Other Average Total");
//Parse lists to session variables
Session["Questions"] = questions;
Session["AverageValue"] = averages;

So the idea of this is that the Chart.aspx will just the render our chart and we don't care if the HTML gets wiped in this web page since we only want the image.

You might be thinking: Why didn't you use a User Control? Well this is one of the first things I tried when trying to resolve this issue which I believe would have been a nicer implementation. Unfortunately, my report page HTML still got rendered as an image.

If anyone knows a better way to output a chart to a webpage, then please leave a comment! Thanks!

Oh yeah, and here is what my Bar Chart looked liked by using the above code: Sample Chart Output

Programmatically Using SqlDataSource

The SqlDataSource control enables you to use a Web control to access data located in a relational data base, including Microsoft SQL Server and Oracle databases, as well as OLE DB and ODBC data sources. You can use the SqlDataSource control with other controls that display data, such as the GridView, FormView, and DetailsView controls, to display and manipulate data on an ASP.NET Web page, using little or no code.

protected void PopulateComments(string recordNo)
    //Connection to database
    string connString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
    SqlDataSource sqlDataSource = 
        new SqlDataSource(connString, "SELECT [CommComments], [RelComments], [ManageComments], [RoleComments], [PersonalComments] FROM [tblSurveyResults] WHERE ([SurveyID] = @SurveyID)");

    sqlDataSource.SelectParameters.Add(new Parameter("SurveyID", System.TypeCode.Int32, recordNo));
    System.Data.DataView dv = (System.Data.DataView)sqlDataSource.Select(DataSourceSelectArguments.Empty);
    //Output Comments to label controls
    lblQuestion1Comments.Text = dv[0][0].ToString();
    lblQuestion2Comments.Text = dv[0][1].ToString();
    lblQuestion3Comments.Text = dv[0][2].ToString();
    lblQuestion5Comments.Text = dv[0][3].ToString();
    lblQuestion4Comments.Text = dv[0][4].ToString();

As you can see, the data is output from the database in little code. I believe this is far more flexible compared to dragging a dropping a SqlDataSource onto the page. The above code queries the database and then passes the selected fields to a DataView. You can then output each individual column data where you want. In this case, I have output the data to labels:

//Output Comments to label controls
lblQuestion1Comments.Text = dv[0][0].ToString(); //Output CommComments column data
lblQuestion2Comments.Text = dv[0][1].ToString(); //Output RelComments column data
lblQuestion3Comments.Text = dv[0][2].ToString(); //Output ManageComments column data
lblQuestion4Comments.Text = dv[0][3].ToString(); //Output RoleComments column data
lblQuestion5Comments.Text = dv[0][4].ToString(); //Output PersonalComments column data

Simple Way To Use A DataTable

When I normally create a datatable, I use quite a few lines of code just to add columns and input data into my DataTable.  But recently I have been using the following method use a DataTable in my code. The following function validates RadionButtonLists that I have in my page by passing the RadioButtonList size (rblSize) and RadioButtonList name (rblName).

//Function: Validate RadioButtonList for each question group
bool GroupValidateRBL(int rblSize, string rblName)
    bool validateOutput = true;
    int counter = 1;
    //Create DataTable object
    DataTable dt = new DataTable();

    //Add columns to DataTable

    while (counter <= rblSize)
        ContentPlaceHolder cph = (ContentPlaceHolder)Page.Master.FindControl("ContentPlaceHolder1");
        RadioButtonList rbl = (RadioButtonList)cph.FindControl(rblName + counter);

       //Add Rows to Datatable
       dt.Rows.Add(new string[] { counter.ToString(), rblName, rbl.SelectedIndex.ToString() });

    //Iterate through all rows in the DataTable to find all RadioButtonLists that have not been selected
    foreach (DataRow dr in dt.Rows)
        if (Convert.ToInt32(dr["Checked"]) == -1)
            validateOutput = false;
   return validateOutput;

The DataTable in the function above stores a list of RadioButtonList entries and then iterates through each row in the DataTable to see if they have been selected. The data is entered into the DataTable by the following line:

dt.Rows.Add(new string[] { counter.ToString(), rblName, rbl.SelectedIndex.ToString() });