For some strange reasons, I want to write HTML directly to the Response stream from a controller action. (I understand MVC separation, but this is a special case.)
C
I used a class derived from FileResult to achieve this using normal MVC pattern:
///
/// MVC action result that generates the file content using a delegate that writes the content directly to the output stream.
///
public class FileGeneratingResult : FileResult
{
///
/// The delegate that will generate the file content.
///
private readonly Action content;
private readonly bool bufferOutput;
///
/// Initializes a new instance of the class.
///
/// Name of the file.
/// Type of the content.
/// Delegate with Stream parameter. This is the stream to which content should be written.
/// use output buffering. Set to false for large files to prevent OutOfMemoryException.
public FileGeneratingResult(string fileName, string contentType, Action content,bool bufferOutput=true)
: base(contentType)
{
if (content == null)
throw new ArgumentNullException("content");
this.content = content;
this.bufferOutput = bufferOutput;
FileDownloadName = fileName;
}
///
/// Writes the file to the response.
///
/// The response object.
protected override void WriteFile(System.Web.HttpResponseBase response)
{
response.Buffer = bufferOutput;
content(response.OutputStream);
}
}
The controller method would now be like this:
public ActionResult Export(int id)
{
return new FileGeneratingResult(id + ".csv", "text/csv",
stream => this.GenerateExportFile(id, stream));
}
public void GenerateExportFile(int id, Stream stream)
{
stream.Write(/**/);
}
Note that if buffering is turned off,
stream.Write(/**/);
becomes extremely slow. The solution is to use a BufferedStream. Doing so improved performance by approximately 100x in one case. See
Unbuffered Output Very Slow