2011-12-14 110 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的早期版本嘗試相同的代碼給我的東西「不能追加頭「錯誤。我不記得我是如何解決這個問題的,但是這並不容易。如果您認爲這種情況適用於您,我可以通過舊項目搜索固定代碼。

希望它可以幫助