Reputation: 1454
I just upgraded an ASP.NET project from .NET 2.0 to 4.0. Still using MVC 2. Some functionality that sends back .csv files was (oddly) written as a view. Then, in the MainContentPlaceHolder section, the code threw away all the content from the Master:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/MyMaster" Inherits="System.Web.Mvc.ViewPage<MyViewModel>" %>
<%
HttpContext context = HttpContext.Current;
context.Response.Clear();
context.Response.Write(Html.CompletionByTemplateExport((CompletionByTemplateExport)ViewData["report"]));
context.Response.ContentType = "text/csv";
context.Response.AppendHeader("Content-Disposition", "attachment; filename=CompletionByTemplateReport.csv");
context.Response.End();
%>
After the upgrade to .NET 4.0, this workaround doesn't work any more: the .csv file contains all the html content that was output by the master page.
What has changed about the way the request and response are processed, in the upgrade to .NET 4.0? Is there a way to make it behave the old way, so that response.Clear() and Response.End() work as they used to? I'm looking for a short-term solution until the .csv-downloading functionality can be rewritten.
Upvotes: 3
Views: 6723
Reputation: 31
I solved a similar problem by adding a header indicating the file size.
It makes no sense to me, but it works.
With Response
.Buffer = True
.ClearContent()
.ClearHeaders()
.ContentType = "text/csv"
.AppendHeader("content-disposition", "attachment; filename=" & fileName)
.AppendHeader("Content-Length", buffer.Length)
.OutputStream.Write(buffer, 0, buffer.Length)
.Flush()
End With
Upvotes: 0
Reputation: 59397
I'm not exactly sure how, but it does seem as though the page life-cycle has changed slightly between .NET 2.0 and .NET 4.0. I was able to duplicate the problem.
I assume your view looks something like this:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/MyMaster" Inherits="System.Web.Mvc.ViewPage<MyViewModel>" %>
<asp:Content Id="MainContent1" ContentPlaceHolderID="MainContent">
<%
HttpContext context = HttpContext.Current;
context.Response.Clear();
context.Response.Write(Html.CompletionByTemplateExport((CompletionByTemplateExport)ViewData["report"]));
context.Response.ContentType = "text/csv";
context.Response.AppendHeader("Content-Disposition", "attachment; filename=CompletionByTemplateReport.csv");
context.Response.End();
%>
</asp:Content>
Unfortunately, I believe you'd have to do something like this:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/MyMaster" Inherits="System.Web.Mvc.ViewPage<MyViewModel>" %>
<script runat="server">
void Page_Load(object sender, EventArgs args) {
HttpContext context = HttpContext.Current;
context.Response.Clear();
context.Response.Write(Html.CompletionByTemplateExport((CompletionByTemplateExport)ViewData["report"]));
context.Response.ContentType = "text/csv";
context.Response.AppendHeader("Content-Disposition", "attachment; filename=CompletionByTemplateReport.csv");
context.Response.End();
}
</script>
Or (better yet), move that code into the controller (since this is MVC):
public class MyController : Controller
{
public ActionResult Index()
{
// This is redundant, Controllers and Views have a Response property
// HttpContext context = HttpContext.Current;
CompletionByTemplateExport reportData = ...;
Response.Clear();
Response.Write(Html.CompletionByTemplateExport(reportData));
Response.ContentType = "text/csv";
Response.AppendHeader("Content-Disposition", "attachment; filename=CompletionByTemplateReport.csv");
Response.End();
}
}
Either of those will give you just the CSV with no master page HTML.
Upvotes: 2