Steve Smith's Blog

Musings on Software and the Developer Community

Render Control as String

When working with AJAX and Web Services it's often nice to be able to render ASP.NET controls as strings, so the rendered HTML can be sent back to the client to replace the contents of a <div> or something like that.  The standard way of achieving this is to use the RenderControl() method, exposed by all ASP.NET controls.  Unfortunately, the RenderControl() method doesn't simply return a string - that would be too easy.  Instead, it takes in an HtmlTextWriter which it will render the control into.  No problem, just new one of those up and... not so fast.  You can't actually create an instance of an HtmlTextWriter without first having a TextWriter.  And since you really want a string when this is all said and done, a StringBuilder would be nice to have as well.  So, a few using() statements later, you end up with something like this as the basic pattern:

StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
    using (HtmlTextWriter textWriter = new HtmlTextWriter(sw))
    {
        myControl.RenderControl(textWriter);
    }
}
return sb.ToString();

You can take this technique and apply it to a real control in a web method like this example, that renders a Panel with two Label controls in it.

[WebMethod]
public string GetPanel()
{
    Panel myPanel = new Panel();
    Label myLabel1 = new Label();
    myLabel1.Text = "First Label";
    Label myLabel2 = new Label();
    myLabel2.Text = "Second Label";
    myPanel.Controls.Add(myLabel1);
    myPanel.Controls.Add(myLabel2);
 
    StringBuilder sb = new StringBuilder();
    using (StringWriter sw = new StringWriter(sb))
    {
        using (HtmlTextWriter textWriter = new HtmlTextWriter(sw))
        {
            myPanel.RenderControl(textWriter);
        }
    }
    return sb.ToString();
}

I have another blog post on how to render a user control as a string if that is what you really want to do.

The thing to notice about this code for rendering an ASP.NET control as a string is that it's rather repetitive and verbose.  However, it also is the same for any System.Web.UI.Control, and so it is an excellent candidate for an extension method.  Add something like this to a namespace that is referenced in your code to create the extension method:

public static class ControlExtenders
{
    public static string RenderControl(this Control control)
    {
        StringBuilder sb = new StringBuilder();
        using (StringWriter sw = new StringWriter(sb))
        {
            using (HtmlTextWriter textWriter = new HtmlTextWriter(sw))
            {
                control.RenderControl(textWriter);
            }
        }
        return sb.ToString();
    }
}

Now the code to render a control becomes simply myControl.RenderControl();.  Our GetPanel() web method can be rewritten to use the extension method like so:

[WebMethod]
public string GetPanel()
{
    Panel myPanel = new Panel();
    Label myLabel1 = new Label();
    myLabel1.Text = "First Label";
    Label myLabel2 = new Label();
    myLabel2.Text = "Second Label";
    myPanel.Controls.Add(myLabel1);
    myPanel.Controls.Add(myLabel2);
 
    return myPanel.RenderControl(); // extension method
}

I discussed this approach briefly on a recent interview on Craig Shoemaker's Polymorphic Podcast.  You can listen to the show here.

kick it on DotNetKicks.com

Subscribe to Steve's Blog

kick it on DotNetKicks.com

Thursday, 28 August 2008

Comments

 avatar

Jarrett said on 01 Sep 2008 at 3:01 PM

Note: this only works when you have a HttpContext. If you try rendering a control outside of Asp.Net runtime (such as a non-hosted WCF service), it will not work.


 avatar

Mike Borozdin said on 04 Sep 2008 at 8:14 AM

I like the way you implemented that with extension methods, they really come very handy.


 avatar

asp.net developer said on 05 Sep 2008 at 1:06 PM

it's simple to use in simple apps.


 avatar

PhanCongPhuoc said on 02 Apr 2009 at 4:41 AM

I use your function, but I get the error message that : Control 'Mydiv' of type 'RadioButton' must be placed inside a form tag with runat=server.

But I use master page, and take the form there

How can I solve it

Thank you


 avatar

ramzi said on 03 May 2009 at 12:13 PM

somehow the dynamic VS compiler won't swallow

return myPanel.RenderControl(), asking for a stringwriter, hence

in a simple asp.net page, in the coderbehind, the method can be called as:

return ControlExtenders.RenderControl(i1);

it does the trick, misses the point of extenders, but works.


 avatar

Jeremy said on 12 May 2009 at 12:51 PM

When I try to render a Panel or a Label, this works great. However, when I try to render an AJAX control, more specifically the TabContainer, I get the ever-helpful "...not set to an instance of an object" error.

Any thoughts?


Leave a Comment

Please join the discussion and share your thoughts.