ASP.NET Web Forms Response.Write in an UpdatePanel #dev #web

I recently had a problem at work where I wanted to use some code that writes to the Response.Output TextWriter, this works fine until you stick an UpdatePanel around the line that writes to it. Various searches on the internet didn’t reveal any clues as to how to do this, all that I found suggested alternatives and used words like “doesn’t work” and use “PostBackTrigger” (which, by the way, negates the whole point of an UpdatePanel).

For fear of being labelled a hack-it together guy, I came up with two solutions, one is rock solid, the other is less so, but works wonderfully until they change how UpdatePanels work (which is unlikely given the fact that Web Forms is a dying technology, if you disagree then we will never be friends).

The basis of the solution

A control (anything inheriting from WebControl) is given a TextWriter on RenderBeginTag, RenderEndTag, … etc. Ah (ching, the penny drops), maybe this is different from Response.Output when we are processing an Async Postback? Indeed it is!

An example where Response.Output.Write doesn’t work

This is the standard Web Forms template application with the content removed.

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ResponseWriteUpdatePanel._Default" %>
<asp:Content runat="server" ID="FeaturedContent" ContentPlaceHolderID="FeaturedContent">
</asp:Content>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
    <asp:UpdatePanel runat="server">
        <ContentTemplate>
            <% Response.Output.Write("Hello"); %>
            <asp:TextBox Text="Text Here" ID="MyTextBox" runat="server" />
            <asp:Button Text="Button" ID="MyButton" runat="server" />
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

Click the button and the Response.Output.Write destroys the response:

Unhandled exception at line 1, column 126350 in http://localhost:49213/bundles/MsAjaxJs?v=J4joXQqg80Lks57qbGfUAfRLic3bXKGafmR6wE4CFtc1

0x800a139e – JavaScript runtime error: Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.

Details: Error parsing near ‘1|#||4|Hello245|updatePanel’.

Here’s a server control that captures the TextWriter and sticks it into the Response.Output (this is the less so option):

using System.Web.UI;
using System.Web.UI.WebControls;

namespace ResponseWriteUpdatePanel
{
    public class MyResponseHelper : WebControl
    {
        public override void RenderBeginTag(HtmlTextWriter output)
        {
            this.Page.Response.Output = output;
        }

        public override void RenderEndTag(HtmlTextWriter output)
        {
        }

        protected override void RenderContents(HtmlTextWriter output)
        {
        }
    }
}

Then add to the page, like so:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ResponseWriteUpdatePanel._Default" %>
<%@ Register TagPrefix="tim" Namespace="ResponseWriteUpdatePanel" Assembly="ResponseWriteUpdatePanel" %>
<asp:Content runat="server" ID="FeaturedContent" ContentPlaceHolderID="FeaturedContent">
</asp:Content>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
    <asp:UpdatePanel runat="server">
        <ContentTemplate>
            <tim:MyResponseHelper ID="MyOutput" runat="server"></tim:MyResponseHelper>
            <% Response.Output.Write("Hello"); %>
            <asp:TextBox Text="Text Here" ID="MyTextBox" runat="server" />
            <asp:Button Text="Button" ID="MyButton" runat="server" />
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

Voila, it works.

Next, the more rock solid solution which avoids tinkering with the Response.Output:

using System.Web.UI;
using System.Web.UI.WebControls;

namespace ResponseWriteUpdatePanel
{
    public class MyResponseHelper : WebControl
    {
        public HtmlTextWriter Output { get; set; }

        public override void RenderBeginTag(HtmlTextWriter output)
        {
            Output = output;
        }

        public override void RenderEndTag(HtmlTextWriter output)
        {
        }

        protected override void RenderContents(HtmlTextWriter output)
        {
        }
    }
}

And the page directly uses the TextWriter from the control instead of the Response.Output, like so:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ResponseWriteUpdatePanel._Default" %>
<%@ Register TagPrefix="tim" Namespace="ResponseWriteUpdatePanel" Assembly="ResponseWriteUpdatePanel" %>
<asp:Content runat="server" ID="FeaturedContent" ContentPlaceHolderID="FeaturedContent">
</asp:Content>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
    <asp:UpdatePanel runat="server">
        <ContentTemplate>
            <tim:MyResponseHelper ID="MyOutput" runat="server"></tim:MyResponseHelper>
            <% MyOutput.Output.Write("Hello"); %>
            <asp:TextBox Text="Text Here" ID="MyTextBox" runat="server" />
            <asp:Button Text="Button" ID="MyButton" runat="server" />
        </ContentTemplate>
    </asp:UpdatePanel>
</asp:Content>

Of course, should you have two UpdatePanels on the same page then you would use a MyResponseHelper within each and use that instance.

Advertisements

3 responses to “ASP.NET Web Forms Response.Write in an UpdatePanel #dev #web

  1. I seem to be having an issue when I call the Write routine. When the line executes I get a null reference exception.

    String docBuffer = System.Text.Encoding.UTF8.GetString(buffer);
    MyOutput.Output.Write(docBuffer);

    My string variable has a value, however before the Output.Write line executes Output has a null value. Aside from there being an instantiation issue with the Output value I’m not sure where to look, any pointers?

    Thanks.

    • It’s difficult to say without having the complete code, if you rewind back to my example (assuming that works for you) and built it up to what you have that should help identify where your code is breaking.

      Also try debugging using a breakpoint in the RenderBeginTag. I expect your code fragment is executing before the tag is rendered – hence null.

      Best of luck.

  2. I too am getting a null exception here

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s