views:

191

answers:

2

I'm trying to take an existing bunch of code that was previously on a full .aspx page, and do the same stuff in a .ashx handler.

The code created an HtmlTable object, added rows and cells to those rows, then added that html table the .aspx's controls collection, then added it to a div that was already on the page.

I am trying to keep the code in tact but instead of putting the control into a div, actually generate the html and I'll return that in a big chunk of text that can be called via AJAX client-side.

HtmlTable errors out when I try to use the InnerHtml property (says it isn't supported), and when I try RenderControl, after making first a TextWriter and next an HtmlTextWriter object, I get the error that Page cannot be null.

Has anyone done this before? Any suggestions?

A: 

Another option is to host the ASP.NET HTTP pipeline in your process, render the page to a stream and read the HTML you need to send from the HttpListenerContext.Response.OutputStream stream after the page has been processed.

This article has details: http://msdn.microsoft.com/en-us/magazine/cc163879.aspx

Damien
+2  A: 

*Most recent is above.

OK, even after Matt's update there is a workaround ;)

Firstly, we have to use a page with form inside. Otherwise we won't be able to add a ScriptManager control. One more thing: the ScriptManager control should be the first control in the form. Further is easier:

Page page = new Page();
Button button = new System.Web.UI.WebControls.Button
{
    ID = "btnSumbit",
    Text = "TextButton",
    UseSubmitBehavior = true
};
HtmlForm form = new HtmlForm
{
    ID="theForm"
};
ScriptManager scriptManager = new ScriptManager
{
    ID = "ajaxScriptManager"
};
form.Controls.Add(scriptManager);
form.Controls.Add(button);
page.Controls.Add(form);

using (StringWriter output = new StringWriter())
{
    HttpContext.Current.Server.Execute(page, output, false);

    context.Response.ContentType = "text/plain";
    context.Response.Write(output.ToString());
}

This works. The output is quite large so I decided not to include it into my answer :)


Actually, there is a workaround. Yep, we may render a control in handler.

Firstly, we need a formless page. Because without it we get:

Control 'btnSumbit' of type 'Button' must be placed inside a form tag with runat=server.

public class FormlessPage : Page
{
    public override void VerifyRenderingInServerForm(Control control)
    {
    }
}

Secondly, nobody can prevent us from creating an instance of our FormlessPage page. And now let's add a control there (I decided to add a Button control as an example, but you could use any).

FormlessPage page = new FormlessPage();
Button button = new System.Web.UI.WebControls.Button
{
    ID = "btnSumbit",
    Text = "TextButton",
    UseSubmitBehavior = true
};
page.Controls.Add(button);

Thirdly, let's capture the output. For this we use HttpServerUtility.Execute method:

Executes the handler for the specified virtual path in the context of the current request. A System.IO.TextWriter captures output from the executed handler and a Boolean parameter specifies whether to clear the System.Web.HttpRequest.QueryString and System.Web.HttpRequest.Form collections.

Here is the code:

using (StringWriter output = new StringWriter())
{
    HttpContext.Current.Server.Execute(page, output, false);

    context.Response.ContentType = "text/plain";
    context.Response.Write(output.ToString());
}

The result will be:

<input type="submit" name="btnSumbit" value="TextButton" id="btnSumbit" />

In addition I can recommend ScottGu's article Tip/Trick: Cool UI Templating Technique to use with ASP.NET AJAX for non-UpdatePanel scenarios. Hope, you could find a lot of useful there.

Alex
This works great for 90% of what I need, so thank you so much for that. However, I have 1 snag left. There are Telerik controls that need to be rendered in here. I can add the control, but they need a scriptmanager or it blows up on rendering. I've tried adding one as a control into the page, but then it blows up with an error of object not set to an instance.
Matt Dawdy