We're busy upgrading an ASP.NET MVC 2 Application using the 3.5 framework to an ASP.NET MVC 3 Application running on the 4.0 framework.
There's a page which throws an exception when approached by using the browser back button. To support the browser back button on this page we implemented a system that requests the results for that page anew when arriving back on the page. I have no clear indications where to look for the problem however since I always only find the error
Server cannot append header after HTTP headers have been sent.
With stacktrace
at System.Web.HttpResponse.AppendHeader(String name, String value)
at System.Web.HttpResponseWrapper.AppendHeader(String name, String value)
at System.Web.Mvc.MvcHandler.AddVersionHeader(HttpContextBase httpContext)
at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<BeginProcessRequest>b__2()
at System.Web.Mvc.SecurityUtil.<>c__DisplayClassb`1.<ProcessInApplicationTrust>b__a()
at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f)
at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action)
at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust[TResult](Func`1 func)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state)
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
How come the HTTP headers already have been sent?
Thank you in advance, IvanL
EDIT: I am adding new information and insight I gained while hunting for this problem. The Asynch Controller mention of one of the answers got me wondering. When I found that I had to change the following for the old MVC2 method to work:
[HttpPost, ValidateInput(false)]
public void SearchResultOverview(SearchResultViewModel model, string searchUrl)
{
if (!string.IsNullOrEmpty(searchUrl))
{
searchUrl = searchUrl.Replace("SearchPartial", "SearchPartialInternal");
//NOTE MVC 3
HttpContext.Server.TransferRequest(searchUrl, true);
//NOTE MVC 2
//System.Web.HttpContext.Current.RewritePath(searchUrl, false);
//IHttpHandler httpHandler = new MvcHttpHandler();
//// Process request
//httpHandler.ProcessRequest(System.Web.HttpContext.Current);
}
}
When I looked up the TransferRequest method I found that it Performs an asynchronous execution of the specified URL and preserves query string parameters. ( http://msdn.microsoft.com/en-us/library/system.web.httpserverutility.transferrequest.aspx )
Also there is an Exception being thrown before the exception I posted (I simply missed out on it since I cought the exception late). This exception is:
The SessionStateTempDataProvider class requires session state to be enabled.
at System.Web.Mvc.SessionStateTempDataProvider.SaveTempData(ControllerContext controllerContext, IDictionary`2 values)
at System.Web.Mvc.TempDataDictionary.Save(ControllerContext controllerContext, ITempDataProvider tempDataProvider)
at System.Web.Mvc.Controller.PossiblySaveTempData()
at System.Web.Mvc.Controller.ExecuteCore()
at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)
at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext)
at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<>c__DisplayClassb.<BeginProcessRequest>b__5()
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0()
at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
at System.Web.Mvc.MvcHandler.<>c__DisplayClasse.<EndProcessRequest>b__d()
at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f)
at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action)
at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
So how do I make this work?
3 Answers 3
Good news, today I solved my own problem after more thorough research on the cause of the exceptions. The first link that helped me understand what exactly might be the cause of my exceptions and errors was the following: http://www.eggheadcafe.com/tutorials/asp-net/79c73563-408a-493e-a369-d4b380bce549/aspnet-using-servertransferrequest.aspx
It details the workings of Server.TransferRequest and mentions the all important caveat: Session must be released by the main request before transferring to the child request. Digging deeper into how I would do this with MVC I came across the following post here on stackoverflow: How to simulate Server.Transfer in ASP.NET MVC?
This post in turn pointed me to an extremely important matter to know: throw new ApplicationException("TempData won't work with Server.TransferRequest!"); So I created the TransferResult class that can be found in that post and let the actions that required it return via that point. I found now that this exception was being hit in the specific cases I mentioned before. I myself never used TempData but apparently one of my colleagues did.
Due to the nature of the unimportant data inside I decided to Clear() the TempData before any Server.TransferRequest() which made my exceptions and problems melt like snow to the sun.
I want to thank all people that looked to solve this problem and am glad I can provide a closing conclusion and solution so it may benefit those that are looking at the same problem.
Sincerely, IvanL
This can happen if buffering has been switched off on the page. Buffering means that asp.net waits for the whole request to be completed before sending the response. This means the header can be changed at any time. When buffering is off, the output is sent to the client as it's generated. You can't therefore change the headers at will, as they've already been sent.
From your stacktrace, it appears to be an async controller & I'm wondering if this has anything to do with it. I'm only guessing from what you've posted though.
Update
Correction, the async mention is actually framework code & nothing to do with your code. However from your code above, is SearchResultOverview an action on a controller? If so, then using the methods you are using to transfer execution is I think the cause of your problems.
It causing 2 mvchandlers to execute & they're interfering with each other. Routing would be a better way to redirect the request.
2 Comments
I remember having this problem some time ago. I don't remember the exact conditions, but it had something to do with setting the headers and http status code directly inside a custom action filter.
My goal back then was to show a custom page/message when the user authentication timed out and clicked on an ajax action link (like when he leaves the page open for a while then he comes back and clicks on the link), so asp.net mvc didn't show the default login page inside a div (kind of ugly). I don't have the code at hand right now, but it was something like this:
public class AjaxFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.AddHeader("name", "value");
filterContext.HttpContext.Response.StatusCode = 200;
filterContext.Result = something;
}
base.OnActionExecuting(filterContext);
}
}
The thing is, trying this same code on an earlier version of asp.net mvc gave me the "cannot append header" error. I don't remember how I fixed it, but it wasn't easy anyway. I can search through my old projects for the fixed code if you think this case applies to you.
Hope it helps
4 Comments
Explore related questions
See similar questions with these tags.
at System.Web.Mvc.MvcHandler.AddVersionHeader(HttpContextBase httpContext)which means MVC itself is trying to add a header, but it can't. I did try the solution of the question you linked me withreponse.BufferOutput = truebut it does not work. I always receive this exception and stacktrace.Server.TransferRequest(). It appears however that this method does not work when approached by the browser back button... (it perfectly works when the page is regularly loaded)