4

I'm working with a static class in C#, and am trying to use Control.RenderControl() to get a string / mark-up representation of a Control.

Unfortunately the control (and all child controls) use event bubbling to populate certain values, for example, when instantiating, then calling RenderControl() on the following:

public class MyTest : Control
{
    protected override void OnLoad(EventArgs e)
    {
        this.Controls.Add(new LiteralControl("TEST"));
        base.OnLoad(e);
    }
}

I am returned an empty string, because OnLoad() is never fired.

Is there a way I can invoke a 'fake' page lifecycle? Perhaps use some dummy Page control?

Maarten
  • 22,527
  • 3
  • 47
  • 68
maxp
  • 24,209
  • 39
  • 123
  • 201
  • Just curious: Is there some reason why you want the output as string? Are you saving the output to database or something like that, or is it going to be rendered into the web page at some point? If you just want to do some processing or integrate it in some other part where you're manually writing HTML, you can usually do all this within ASP.NET (eg. using Literal controls for raw HTML, PlaceHolder controls for other server controls etc.). – Luaan Jan 08 '14 at 13:43
  • @Luaan The rendered markup is intended to then be sent as part of an email. – maxp Jan 08 '14 at 13:45
  • 2
    Yeah, in that case, unless you can actually make a "real" ASPX to do the same, MikeC's answer is just great. I don't believe there's another simple way unless you use reflection - the methods involved in handling the page lifetime are usually `internal` or `private`, and those in turn call the `protected` OnLoad etc. methods. Server.Execute, on the other hand, is very much the proper way to execute an HttpHandler. And of course, you could just manually call the `IHttpHandler.ProcessRequest` of the page, but then you're just using more code to do the same thing as `Server.Execute` :) – Luaan Jan 08 '14 at 15:00

1 Answers1

9

I was able to accomplish this by using a local instance of Page and HttpServerUtility.Execute:

// Declare a local instance of a Page and add your control to it
var page = new Page();
var control = new MyTest();
page.Controls.Add(control);

var sw = new StringWriter();            

// Execute the page, which will run the lifecycle
HttpContext.Current.Server.Execute(page, sw, false);           

// Get the output of your control
var output = sw.ToString();

EDIT

If you need the control to exist inside a <form /> tag, then simply add an HtmlForm to the page, and add your control to that form like so:

// Declare a local instance of a Page and add your control to it
var page = new Page();
var control = new MyTest();

// Add your control to an HTML form
var form = new HtmlForm();
form.Controls.Add(control);

// Add the form to the page
page.Controls.Add(form);                

var sw = new StringWriter();            

// Execute the page, which will in turn run the lifecycle
HttpContext.Current.Server.Execute(page, sw, false);           

// Get the output of the control and the form that wraps it
var output = sw.ToString();
mclark1129
  • 7,532
  • 5
  • 48
  • 84
  • Thanks very much. I've just tried it and it works perfectly. As an addendum, if any of the controls needed to be inside a `
    ` then the standard `Page` class must be tweaked. I've uploaded the source here for other's sake. http://pastebin.com/3EKwB8sC
    – maxp Jan 08 '14 at 14:15
  • @maxp It's even easier than that, simply new up an `HtmlForm` and add it to the page. Then you add your control to the `HtmlForm` instead of the page and voila! – mclark1129 Jan 08 '14 at 20:26