Dot Net Tricks

Articles about .NET, ASP.NET, C#, Object Oriented Programming and Agile Methodologies
Welcome to Dot Net Tricks Sign in | Join | Help
in Search

Software Theosophy

Rendering a control as an Html String in ASP.NET 2.0

It sounded simple enough. I wanted to programmatically take the contents of a form, including TextBoxes, drop down lists, checkboxes, etc and email it to my client as a sort of “snapshot” of what the user had filled out on the form.  I had done this countless times in ASP.NET 1.1, but 2.0 refused to budge.  I kept getting error after error.  Here is the basic code I was using.  Since I seem to have a mental blocks on streams, textwriters and any other part of the framework that uses the Decorator pattern I had to look it up:

 

StringWriter swriter = new StringWriter();

HtmlTextWriter twrite = new HtmlTextWriter(swriter);

this.MainPanel.RenderControl(twrite);

string text = swriter.ToString();

 

This gave me the following exception: “Control 'TextBox1' of type 'TextBox' must be placed inside a form tag with runat=server.  I remembered this from my .NET 1.1, and my solution had been to create a server side form on the fly, in the code behind it, place my controls that I wanted to render into that, then render the form.  The code would then look like this:

 

StringWriter swriter = new StringWriter();

HtmlTextWriter twrite = new HtmlTextWriter(swriter);

HtmlForm form = new HtmlForm();

form.Controls.Add(this.MainPanel);

form.RenderControl(twrite);

string text = swriter.ToString();

 

Unfortunately, this code didn’t work either.  I got another exception: “HtmlForm cannot render without a reference to the Page instance.  Make sure your form has been added to the control tree.  This left me puzzled.  I did NOT remember this from asp.net 1.1.  What does the framework care if I create an Html form without binding it to the page?  What’s changed from asp.net 1.1 to 2.0?

 

Still I tried to give it what it wanted with this line of code:

 

form.Page = this.Page;

 

Still, ASP.NET was not satisfied.  I now got another error: “RegisterForEventValidation can only be called during Render();  By now I was cursing Microsoft and spouting obscenities to myself.  Fortunately, only one other developer named Tina was around and she’s used to me by now.


I searched over and over in google for a way of successfully rendering a control as an html string which showed me a bunch of code that worked in 1.1.  Finally, after all my research, I found the answer.  In ASP.NET 2.0, you must do two things.  First override the VerifyRenderingInServerForm() method.  You don’t have to actually do anything in this method, just override it.  This ensures that you don’t have to create the HtmlForm, but you do have to override this method in your page.  Next, you have to set a page directive: EnableEventValidation="false".  This turns off event validation which basically means ASP.NET no longer checks to see if content in your controls contains malicious code.  There is a vague MSDN article here.

 

I don’t know why so much changed since ASP.NET 1.1 that the old code didn’t work.  But my real question to Microsoft is this: Why doesn’t EVERY control have a RenderAsString() method that will automatically do this for me?  Why do I have to jump through all these hoops to get a string from my controls?  This seems like very common functionality.  In any case, these two things got it to work, so you can take a control and render it as a string and email it, save it to disk or whatever.  All the research has been done for you, and here is my final example code.  This example takes the resulting string and stores it to a file on disk, but you could email it, save it to a database or whatever you wanted.

 

Default.aspx

 

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

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <asp:Panel runat="server" ID="MainPanel">

            <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>

            <asp:Button ID="SendButton" runat="server" OnClick="SendButton_Click" Text="Send" /></asp:Panel>

    </div>

    </form>

</body>

</html>

 

 

Default.aspx.cs

 

using System;

using System.Data;

using System.Configuration;

using System.Web;

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.Text;

using System.IO;

 

public partial class _Default : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

 

    }

      protected void SendButton_Click(object sender, EventArgs e)

      {

            StringWriter swriter = new StringWriter();

            HtmlTextWriter twrite = new HtmlTextWriter(swriter);

            this.MainPanel.RenderControl(twrite);

            string text = swriter.ToString();

 

            File.WriteAllText(Server.MapPath("~/output.htm"), text);

      }

 

      public override void VerifyRenderingInServerForm(Control control)

      {

           

      }

}

 

Published Saturday, September 09, 2006 10:00 PM by Fregas
Filed Under: , ,

Comments

 

janettel said:

This article is excellent.  I started down the same path with trying to create a new form..... got the same error you got - thank God for Google!!!

I am new to .NET and this information was invaluable.  Thanks again!!!  You saved me so much time!!!
October 18, 2007 2:44 PM
 

Fregas said:

You're welcome (and I'm sure google appreciates it too.)

I don't know why MS doesn't build this functionality straight into asp.net.  its so basic.
October 18, 2007 3:21 PM
 

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com
December 16, 2007 9:49 PM
 

registerforeventvalidation can only be called said:

June 11, 2008 10:51 AM
 

Mike said:

Hi,

I have the same problem but my code is inside a user web control.  The override to VerifyRenderingInServerForm does not work there.  The EnableEve... is not a property for the <%@Control tag..
Have do you know of any work around for this situation?

This is my page setting: Master Page -> Page -> User Control.

Thanks in advance.
July 30, 2008 10:50 AM
 

Fregas said:

Mike, you can actually modify this property on the parent page, but it requires the use of reflection, because its not made public and is only settable thru the page's directives.  Send me a private message if you still need this and I can send you some code I use to encapsulate this whole process.
August 4, 2008 9:18 AM
Anonymous comments are disabled

About Fregas

Craig is currently the Lead Developer in Fort Worth, Texas for Enilon Group, a web development firm. He has been programming since 3rd grade (using the Commodoore PET) and professionally for the past 7 years. He has written several articles for ASPToday.com and co-authored the book "Beginning Web Programming using VB.NET and Visual Studio .NET" Currently, his favorite programming language is C#, but he has programmed in Visual Basic, T-SQL, Ruby, ColdFusion, ASP 3.0/VBScript, ASP.NET, Javascript, Java and even Pascal. Besides programming, Craig is best known for his cooking and his somewhat offbeat sense of humor.

This Blog

Post Calendar

<September 2006>
SuMoTuWeThFrSa
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

Syndication

Powered by Community Server, by Telligent Systems