2011-12-14 107 views
5

我们正在忙于使用3.5框架将ASP.NET MVC 2应用程序升级到运行在4.0框架上的ASP.NET MVC 3应用程序。ASP.NET MVC 3:服务器在发送HTTP标头后无法追加标头

有一个页面在使用浏览器后退按钮接近时引发异常。为了支持此页面上的浏览器后退按钮,我们实现了一个系统,该页面返回时重新请求该页面的结果。我还没有明确的迹象表明在哪里寻找问题然而,由于我总是只发现错误

Server cannot append header after HTTP headers have been sent. 

随着堆栈跟踪

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) 

怎么会在HTTP标头已经被发送?

谢谢你在前进, IvanL

编辑: 我加入新的信息和见解,我获得了当寻找这个问题。异步控制器提到了其中一个答案让我想知道。当我发现我不得不改变旧MVC2方法如下工作:

[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); 
    } 
} 

当我抬头看TransferRequest方法我发现它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

也有一个例外是在我发布的例外之前抛出(我只是错过了它,因为我迟到了这个例外)。这个例外是:

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) 

那么我该怎么做这项工作?

+2

嗯,让我看看,如果我可以推断出这个psychicly ... ... ...呃..没了..你将不得不提供一些代码。什么标题你追加,什么时候? – 2011-12-14 17:42:35

+1

也许这将帮助: http://stackoverflow.com/questions/2383169/server-cannot-set-status-after-http-headers-have-been-sent-iis7-5 – 2011-12-14 17:46:43

+1

@Mystere人:这就是要点。我不是自己添加任何头文件,似乎从MVC2更改为MVC3创建此问题,因为代码运行良好,没有任何MVC2例外。如果你看一下堆栈跟踪,你会发现:`在System.Web.Mvc.MvcHandler.AddVersionHeader(HttpContextBase httpContext)`这意味着MVC本身试图添加一个头,但它不能。 我确实试过了你用`reponse.BufferOutput = true`连接了我的问题的解决方案,但它不起作用。我总是收到这个异常和堆栈跟踪。 – IvanL 2011-12-15 09:33:22

回答

2

好消息,今天我就例外的原因更深入的研究后解决我自己的问题。第一个链接,帮助我了解究竟是什么可能是我的例外和错误的原因是:http://www.eggheadcafe.com/tutorials/asp-net/79c73563-408a-493e-a369-d4b380bce549/aspnet-using-servertransferrequest.aspx

它详细介绍了Server.TransferRequest的工作原理并提到了所有重要的警告:会话必须由主要请求释放在转移到子请求之前。更仔细地分析我将如何做到这一点与MVC我碰到下面的帖子在这里来了计算器:How to simulate Server.Transfer in ASP.NET MVC?

这篇文章反过来向我指出一个非常重要的事情知道:throw new ApplicationException("TempData won't work with Server.TransferRequest!");所以我创建了一个可以找到TransferResult类在那篇文章中,让那些需要它的操作通过这一点返回。现在我发现这个例外在我之前提到的具体案例中受到了打击。我自己从来没有使用TempData,但显然我的一个同事做到了。

由于内部不重要的数据的性质,我决定在Server.TransferRequest()之前决定使用Clear()的TempData,这使得我的例外和问题像雪一样融化成太阳。

我想感谢所有希望解决这个问题的人,我很高兴能提供一个结论性的结论和解决方案,因此它可能有利于那些看到相同问题的人。

真诚,IvanL

2

如果页面上的缓冲关闭,可能会发生这种情况。缓冲意味着asp.net在发送响应之前等待整个请求完成。这意味着标题可以随时更改。当缓冲关闭时,输出在生成时发送到客户端。因此,您不能随意更改标题,因为它们已经发送。

从你的stacktrace,它似乎是一个异步控制器&我想知道这是否有什么关系。我只是从你发布的内容中猜测出来的。

更新

修正,异步提实际上是框架代码&无关,与你的代码。但是从你上面的代码,在控制器上的操作是SearchResultOverview?如果是这样,那么使用你用来传递执行的方法是我认为你的问题的原因。

它导致2 mvchandlers执行&他们互相干扰。路由将是重定向请求的更好方式。

0

我记得前段时间有这个问题。我不记得确切的条件,但它与直接在自定义操作过滤器中设置标题和http状态代码有关。

当时我的目标是在用户身份验证超时并单击ajax操作链接时显示自定义页面/消息(例如,当他离开页面打开一段时间后,他回来并单击链接) ,所以asp.net mvc没有显示div内的默认登录页面(很丑陋)。我没有手头上的代码的权利,但它是这样的:

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); 
    } 
} 

是,在asp.net的MVC的早期版本尝试相同的代码给我的东西“不能追加头“错误。我不记得我是如何解决这个问题的,但是这并不容易。如果您认为这种情况适用于您,我可以通过旧项目搜索固定代码。

希望它可以帮助