views:

867

answers:

3

Hi,

I have a view rendering a stream using the response BinaryWrite method. This all worked fine under ASP.NET 4 using the Beta 2 but throws this exception in the RC release:

"HttpException" , "OutputStream is not available when a custom TextWriter is used."

<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<%@ Import Namespace="System.IO" %>
<script runat="server">
protected void  Page_Load(object sender, EventArgs e)
{
    if (ViewData["Error"] == null)
    {

        Response.Buffer = true;
        Response.Clear();
        Response.ContentType = ViewData["DocType"] as string;
        Response.AddHeader("content-disposition", ViewData["Disposition"] as string);
        Response.CacheControl = "No-cache";
        MemoryStream stream = ViewData["DocAsStream"] as MemoryStream;
        Response.BinaryWrite(stream.ToArray());
        Response.Flush();
        Response.Close();
    }
}   
</script>


</script>

The view is generated from a client side redirect (jquery replace location call in the previous page using Url.Action helper to render the link of course). This is all in an iframe.

Anyone have an idea why this occurs?

+4  A: 

When a ViewPage begins executing, it assumes certain things about the remainder of the request. The particular thing that is tripping you up is that a ViewPage assumes that the remainder of the request will be a normal HTML or some other textual response, so it switches the response's TextWriter with its own writer.

In your case, you should make a new ActionResult-derived class whose ExecuteResult method encapsulates the logic in your Page_Load method. Your action method should return an instance of your custom class, and the invoker will run the ExecuteResult method at the appropriate time. This bypasses the view engines entirely, which prevents the error you're running in to and gives you a slight performance boost.

Levi
This is the correct answer
Eduardo Molteni
+5  A: 

I did Levi's answer. It's actually super easy. My code writes an image to the response, which is previously gotten from the file system after various checks.

public class BookImageResult : ActionResult
{
    private readonly GraphicReport graphicReport;

    public BookImageResult(GraphicReport graphicReport)
    {
        this.graphicReport = graphicReport;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        var response = context.RequestContext.HttpContext.Response;
        response.Clear();
        response.ContentType = graphicReport.ContentType;
        response.BinaryWrite(graphicReport.Image);
        response.End();
    }
}

The line at the end of the controller just looks like this:

return new BookImageResult(graphicReport);

Someone mark Levi's response as the answer!

Chris
Thanks for a adding a code sample.
Eduardo Molteni
A: 

Someone buy Levi a beer. Thanks dude. Great solution.

Vinny Brown