When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article
Jobs

ASP ASP.NET ASP FAQs Message Board Feedback ASP Jobs
 
Print this Page!
Published: Wednesday, September 11, 2002

Emailing the Rendered Output of an ASP.NET Web Control

By Scott Mitchell


A Follow-Up Article is Available!
If you try out the code discussed in this article you'll find that while this technique and code works well for DataGrids that just contain BoundColumns or TemplateColumns without Buttons or LinkButtons, it breaks when the DataGrid is configured for sorting or paging or contains ButtonColumn, EditCommandColumn, or TemplateColumns with Buttons or LinkButtons. The follow-up article - Enhancing the 'Email the Rendered Output of an ASP.NET Web Control' Code - discusses why this problem arises and examine a workaround.

For an example of emailing the rendered output of an ASP.NET Web control using ASP.NET 2.0, see: Emailing the Rendered Output of an ASP.NET Web Control in ASP.NET 2.0.

Introduction


Last week I received an email on one of the many lists I was on from Dave Wanta, developer of aspNet Email and Web master of 123ASPX.com. In his email, Dave shared a URL that demonstrated how to use his product (aspNet Email) to mail a rendered DataGrid Web control in an HTML-formatted email. That is, a user, who was viewing a DataGrid control on a Web site's ASP.NET Web page, could provide her email address and click a button to have the DataGrid's output emailed to her.

- continued -

This concept really piqued my interest, and although Dave has provided the source code for his approach, I wanted to figure it out on my own. With some poking around in the .NET Framework documentation I was able to figure it all out in a relatively short amount of time (15 minutes or so). I think this is much more of a testament to the power and ease of use of the .NET Framework than it is my abilities.

Rendering a Control


It is important to understand that when you add a control to a Web page when the page is requested the control is "rendered" into HTML. For example, say that in your ASP.NET Web page you add the following ASP.NET Web control:

<asp:Label runat="server" id="lblMessage" Text="Hello, World!"
     Font-Name="Verdana" Font-Size="10pt" Font-Italic="True" />

When the page is rendered the following HTML will be produced for this Web control:

<span id="lblMessage" style="font-family:Verdana;font-size:10pt;font-style:italic;">Hello, World!</span>

This rendered HTML is then sent to the client. The important information to understand here is that all ASP.NET Web controls are rendered down into some sort of HTML markup.

You may be wondering how this rendering happens, and how all controls can provide this functionality. First, realize that all ASP.NET Web controls are derived from the Controls class (a class in the .NET Framework). This class provides some base properties and methods that all of these controls contain. One of the more important methods is the Render method, which accepts as a single input parameter an object of type HtmlTextWriter. Each Web control overrides this method; inside this method, the control is responsible for generating its proper HTML markup and writing this markup to the HtmlTextWriter parameter.

Retrieving a Control's Rendered HTML in an ASP.NET Page


In order to email someone the HTML rendering of an ASP.NET Web control we'll need to first be able to retrieve a control's HTML and store it in a string variable. Since each control has a Render method, it would seem to make sense that we could just pass in an HtmlTextWriter, let the control render itself to the HtmlTextWriter, and then read the HTML content stored in this HtmlTextWriter.

Things aren't quite that simple, though. First off, the Render method is a protected method, meaning that only methods within the class itself or derived from the class may call it. Fortunately, however, the Control class provides a public RenderControl method. This method, like the protected Render method, accepts an HtmlTextWriter as its sole input parameter. So, we can use RenderControl in place of Render. Problem #1 solved.

The second difficulty that arises is that the HtmlTextWriter, as its name implies, is for writing information to. That is, it has methods like Write and WriteLine, but no corresponding Read methods. Essentially the HtmlTextWriter class serves as a means to only write data to some backing store. When the ASP.NET page is rendering the controls, preparing to send this HTML to the client, I would assume the backing store is some kind of network stream. However, we want our backing store to be a simple string.

It took a bit of pecking through the documentation, but I found that the HtmlTextWriter class's constructor will accept a TextWritter instance. The TextWritter class, though, is an abstract one, meaning you cannot use the class as-is; rather, you have to use one of the classes that inherits the TextWritter class. One such class that is derived from the TextWritter class is the StringWriter class. The StringWriter class can use as a backing store a StringBuilder, which can be used to return a string. Phew!

So, in order to retrieve the rendered HTML of a Web control we have to do the following:

  1. Create an instance of the StringBuilder class.
  2. Create an instance of the StringWriter class, using the StringBuilder class from (1) as its backing store.
  3. Create an instance of the HtmlTextWriter class, using the StringWriter class from (2) as its backing store.
  4. Call the RenderControl method of the control whose rendered HTML we are interested in, passing in the HtmlTextWriter instance from (3).

At this point we can retrieve the control's rendered HTML as a string by accessing the StringBuilder instance's ToString() method.

Retrieving a Control's Rendered HTML - in Action


Ok, by this point you're likely thoroughly confused. Understandably, a discussion on these topics can be tricky and quite wordy. By looking at some code, though, hopefully things will start to clear up. The following code demonstrates how to read the rendered HTML from a data bound DataGrid Web control. As you can see, retrieving the rendered HTML is only a matter of a few lines of code.

<% @Import Namespace="System.IO" %>
<% @Import Namespace="System.Data" %>
<% @Import Namespace="System.Data.SqlClient" %>
<script language="vb" runat="server">
  Sub Page_Load(sender as Object, e as EventArgs)
    '1. Create a connection
    Dim myConnection as New SqlConnection(ConfigurationSettings.AppSettings("connectionString"))

    '2. Create the command object, passing in the SQL string
    Const strSQL as String = "sp_Popularity"
    Dim myCommand as New SqlCommand(strSQL, myConnection)

    'Set the datagrid's datasource to the datareader and databind
    myConnection.Open()
    dgPopularFAQs.DataSource = myCommand.ExecuteReader(CommandBehavior.CloseConnection)
    dgPopularFAQs.DataBind()	


    'Get the rendered HTML
    Dim SB as New StringBuilder()    
    Dim SW as New StringWriter(SB)
    Dim htmlTW as New HtmlTextWriter(SW)
    dgPopularFAQs.RenderControl(htmlTW)
    
    Dim dataGridHTML as String = SB.ToString()
    
    ltlHTMLOutput.Text = Server.HtmlEncode(dataGridHTML)
  End Sub
</script>

  <asp:datagrid id="dgPopularFAQs" runat="server"
        AutoGenerateColumns="False"
        Font-Name="Verdana"  Width="85%"
        HorizontalAlign="Center"
        ItemStyle-Font-Size="9pt"
        AlternatingItemStyle-BackColor="#dddddd">
     
     <HeaderStyle BackColor="Navy" ForeColor="White" Font-Bold="True"
          Font-Size="13pt" HorizontalAlign="Center" /> 
       
     <Columns>
       <asp:BoundColumn HeaderText="FAQ ID" DataField="FAQID"
               ItemStyle-HorizontalAlign="Center" />
       <asp:BoundColumn HeaderText="Question" DataField="Description" />
       <asp:BoundColumn HeaderText="Total Views" DataField="ViewCount"
              DataFormatString="{0:#,###}" ItemStyle-HorizontalAlign="right" />
     </Columns>
  </asp:DataGrid>
  <p>Below you will see the rendered HTML for the DataGrid Web control</p>
  <pre>
    <asp:literal id="ltlHTMLOutput" runat="server" />
  </pre>
[View a Live Demo!]

All of the action's happening in the bolded text in the Page_Load event handler. There a StringBuilder instance is created, which is used as the backing store for a StringWriter object. Next, the HtmlTextWriter object is created, using the StringWriter object as its backing store. Finally, the DataGrid dgPopularFAQs has its RenderControl method called. After this has finished we can retrieve the rendered HTML by calling the StringBuilder object's ToString() method.

As the live demo shows, this example simply outputs the rendered HTML of the DataGrid onto the ASP.NET Web page. An ASP.NET literal control (ltlHTMLOutput) is used to hold the rendered HTML. At the end of the Page_Load event handler the literal control's Text property is set to the DataGrid's rendered HTML. Of course, we use Server.HtmlEncode first so that < are converted into &lt; and so forth, so that we see the actual HTML rather than the HTML as it is normally displayed in the browser.

Emailing a Control's Rendered HTML


One of the neat things you can do, once you have the rendered HTML of a Web control, is email it using HTML-formatted email! For example, if you run an eCommerce store and you use a Web control to, say, display the user's bill, you could have the user automatically receive a copy of this bill via email. You wouldn't have to write a line of code to do any special formatting for the email version of the bill - just send an HTML-formatted email whose body is set to the rendered HTML of the bill you are wanting to send.

Below you will find a demo for emailing a Web control to a user via HTML-formatted email. I am not including a live demo for this example because I don't want anyone to abuse the demo to start sending floods of email to folks they might not like. Instead, I'll show you a simple example in code and let you run it on your own servers.

<% @Import Namespace="System.Web.Mail" %>
<% @Import Namespace="System.IO" %>
<% @Import Namespace="System.Data" %>
<% @Import Namespace="System.Data.SqlClient" %>
<script language="vb" runat="server">
  Sub Page_Load(sender as Object, e as EventArgs)
    If Not Page.IsPostBack then
      BindData()
    End If
  End Sub
	
	
  Sub BindData()
    '1. Create a connection
    Dim myConnection as New SqlConnection(ConfigurationSettings.AppSettings("connectionString"))

    '2. Create the command object, passing in the SQL string
    Const strSQL as String = "sp_Popularity"
    Dim myCommand as New SqlCommand(strSQL, myConnection)

    'Set the datagrid's datasource to the datareader and databind
    myConnection.Open()
    dgPopularFAQs.DataSource = myCommand.ExecuteReader(CommandBehavior.CloseConnection)
    dgPopularFAQs.DataBind()	
  End Sub
  
  
  Sub EmailDataGrid(sender as Object, e as EventArgs)
    Dim SB as New StringBuilder()    
    Dim SW as New StringWriter(SB)
    Dim htmlTW as New HtmlTextWriter(SW)
    dgPopularFAQs.RenderControl(htmlTW)
    
    Dim dataGridHTML as String = SB.ToString()
    
    'Now, send the email
	'Create an instance of the MailMessage class
	Dim objMM as New MailMessage()

	'Set the properties
	objMM.To = txtEmailAddy.Text
	objMM.From = "YourEmailAddress"

	'Send the email in HTML format
	objMM.BodyFormat = MailFormat.Html

	'Set the subject
	objMM.Subject = "DataGrid Emailing"

	'Set the body - use VbCrLf to insert a carriage return
	objMM.Body = "<font face=""Verdana"">This is an example of emailing a " & _
	             "DataGrid Web control via an ASP.NET Web page." & dataGridHTML
	
	SmtpMail.Send(objMM)
	
	Response.Write("<i>Email sent to " & txtEmailAddy.Text & "!</i>")
  End Sub
</script>

<form runat="server">
  <asp:datagrid id="dgPopularFAQs" runat="server"
        AutoGenerateColumns="False"
        Font-Name="Verdana"  Width="85%"
        HorizontalAlign="Center"
        ItemStyle-Font-Size="9pt"
        AlternatingItemStyle-BackColor="#dddddd">
     
     <HeaderStyle BackColor="Navy" ForeColor="White" Font-Bold="True"
          Font-Size="13pt" HorizontalAlign="Center" /> 
       
     <Columns>
       <asp:BoundColumn HeaderText="FAQ ID" DataField="FAQID"
               ItemStyle-HorizontalAlign="Center" />
       <asp:BoundColumn HeaderText="Question" DataField="Description" />
       <asp:BoundColumn HeaderText="Total Views" DataField="ViewCount"
              DataFormatString="{0:#,###}" ItemStyle-HorizontalAlign="right" />
     </Columns>
  </asp:DataGrid>

  <p>
  <asp:TextBox id="txtEmailAddy" runat="server" />
  <asp:Button Text="Email DataGrid" OnClick="EmailDataGrid" runat="server" />
</form>

For more information on sending email through an ASP.NET Web page be sure to check out: Sending Email from an ASP.NET Web Page. A screenshot of the emailed DataGrid control can be seen below. You can also view a high quality image of the screenshot below (~100 KB).

A screenshot of the emailed DataGrid.

A Follow-Up Article is Available!
If you try out the code discussed in this article you'll find that while this technique and code works well for DataGrids that just contain BoundColumns or TemplateColumns without Buttons or LinkButtons, it breaks when the DataGrid is configured for sorting or paging or contains ButtonColumn, EditCommandColumn, or TemplateColumns with Buttons or LinkButtons. The follow-up article - Enhancing the 'Email the Rendered Output of an ASP.NET Web Control' Code - discusses why this problem arises and examine a workaround.

For an example of emailing the rendered output of an ASP.NET Web control using ASP.NET 2.0, see: Emailing the Rendered Output of an ASP.NET Web Control in ASP.NET 2.0.

Conclusion


In this article we examined how to programmatically retrieve the HTML that is rendered by an ASP.NET Web control. While our examples focused on retrieving the rendered HTML of a DataGrid, the same code will work for any ASP.NET Web control. One useful implementation of this knowledge is in sending users an HTML-formatted email that contains the output of an ASP.NET Web control, as shown in the last example in this article.

Happy Programming!

  • By Scott Mitchell



  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article