How to perform the same thing as Response.BinaryWrite

734 views
Skip to first unread message

Dennis

unread,
Sep 2, 2009, 12:15:59 AM9/2/09
to FubuMVC Development Group
I want to be able to return a PDF from a document storage system. In
WebForms you would do something like this...

Response.ClearHeaders();
Response.ClearContent();
Response.ContentType = "application/pdf";
Response.Buffer = true;
Response.BinaryWrite(pdfbytes);
Response.End();

How can I do the same thing with FubuMVC?

I have tried doing the above in the "view" itself, but I recieve the
following:
"OutputStream is not available when a custom TextWriter is used"

After studying the ASP.NET Response class in Reflector for this error
and evaluating the code in FubuMVC I have not been able to figure this
out.

Thanks
Dennis

Chad Myers

unread,
Sep 2, 2009, 1:56:25 AM9/2/09
to fubumv...@googlegroups.com
That would be a new type of action result. Do not try to do this through an ASPX/View/etc.

You could do it through a behavior, perhaps, but I would be recommend having a controller action that handles this, which returns a result override that performs this low-level stuff (streaming binary to the client).

It would be similar to the Json Result:

Create a PdfResult object like JsonResult

I would also abstract out the dirty bits of messing with the HttpResponse object like I did with IOutputWriter.

You might consider having an IMimeFileWriter or something that's like IOutputWriter, but also knows about 'content type' and other MIME-type things. 

-Chad

Dennis

unread,
Sep 8, 2009, 11:55:16 PM9/8/09
to FubuMVC Development Group
@Chad: Let me know what you think....

public class output_as_mime_type : behavior_base_for_convenience
{
readonly IMimeOutputWriter mimeOutputWriter;

public output_as_mime_type(IMimeOutputWriter mimeOutputWriter)
{
this.mimeOutputWriter = mimeOutputWriter;
}

public override OUTPUT AfterInvocation<OUTPUT>(OUTPUT output,
IInvocationResult insideResult)
{
var mimeResult = output as MimeResult;
if (mimeResult != null) mimeOutputWriter.Write
(mimeResult);

return base.AfterInvocation(output, insideResult);
}
}

public class MimeResult
{
public byte[] Content { get; set; }
public string MimeType { get; set; }
public object FileName { get; set; }
}

public interface IMimeOutputWriter
{
void Write(MimeResult mimeResult);
}

public class HttpResponseMimeOutputWriter : IMimeOutputWriter
{
public void Write(MimeResult mimeResult)
{
var response = HttpContext.Current.Response;
response.ContentType = mimeResult.MimeType;
response.AddHeader("Content-Disposition", string.Format
("Filename={0}", mimeResult.FileName));
response.Buffer = true;
response.BinaryWrite(mimeResult.Content);
}
}

Chad Myers

unread,
Sep 9, 2009, 12:14:15 PM9/9/09
to fubumv...@googlegroups.com
It looks good except that I think MimeResult should be an IInvocationResult, not an output model.

The output model should contain the filename or the binary blog which the MimeResult will use to stream to the browser.

Or rather, the output model should contain everything MimeResult will need to properly return the result to the browser. I'll leave it up to you to determine what all that needs to be (looks like Output/Browser Filename, physical file or binary blob of data to send, mime type, and maybe content length).

-Chad

Dennis

unread,
Sep 12, 2009, 10:33:41 AM9/12/09
to FubuMVC Development Group
@Chad: So more like this....

public class output_if_mime_output : behavior_base_for_convenience
{
public override OUTPUT AfterInvocation<OUTPUT>(OUTPUT output,
IInvocationResult insideResult)
{
Result = output is IMimeOutput ? new RenderMimeResult
((IMimeOutput)output) : insideResult;
return output;
}
}

public interface IMimeOutput
{
byte[] Content { get; }
string MimeType { get; }
string FileName { get; }
}

public class MimeOutput : IMimeOutput
{
readonly string mimeType;
readonly byte[] content;
readonly string fileName;

public MimeOutput(string mimeType, string fileName, byte[]
content)
{
this.mimeType = mimeType;
this.content = content;
this.fileName = fileName;
}

public byte[] Content
{
get { return content; }
}

public string MimeType
{
get { return mimeType; }
}

public string FileName
{
get { return fileName; }
}
}

public class RenderMimeResult : IInvocationResult
{
readonly IMimeOutput mimeOutput;

public RenderMimeResult(IMimeOutput mimeOutput)
{
this.mimeOutput = mimeOutput;
}

public void Execute(IServiceLocator locator)
{
var writer = locator.GetInstance<IMimeOutputWriter>();
writer.Write(mimeOutput);
}
}

public interface IMimeOutputWriter
{
void Write(IMimeOutput mimeOutput);
}

public class HttpResponseMimeOutputWriter : IMimeOutputWriter
{
public void Write(IMimeOutput mimeOutput)
{
var response = HttpContext.Current.Response;
response.ContentType = mimeOutput.MimeType;
response.AddHeader("Content-Disposition", string.Format
("Filename={0}", mimeOutput.FileName));
response.Buffer = true;
response.BinaryWrite(mimeOutput.Content);
}
}

Chad Myers

unread,
Sep 14, 2009, 11:35:23 AM9/14/09
to fubumv...@googlegroups.com
Yeah, that looks better!

I know it seems like some extra work, but it'll be worth it if you ever have to fix problems or add features.

-Chad
Reply all
Reply to author
Forward
0 new messages