2011-12-14 11 views
5

Siamo impegnati nell'aggiornamento di un'applicazione ASP.NET MVC 2 utilizzando il framework 3.5 a un'applicazione ASP.NET MVC 3 in esecuzione sul framework 4.0.ASP.NET MVC 3: il server non può aggiungere l'intestazione dopo che le intestazioni HTTP sono state inviate

C'è una pagina che genera un'eccezione quando ci si avvicina utilizzando il pulsante Indietro del browser. Per supportare il pulsante Indietro del browser su questa pagina abbiamo implementato un sistema che richiede nuovamente i risultati per quella pagina quando si ritorna sulla pagina. Non ho indicazioni chiare dove cercare per il problema comunque dato che ho sempre e solo trovare l'errore

Server cannot append header after HTTP headers have been sent. 

Con 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) 

Come mai le intestazioni HTTP già sono stati inviati?

Grazie in anticipo, IvanL

EDIT: sto aggiungendo nuove informazioni e intuizione ho guadagnato durante la caccia per questo problema. Il nominativo di Asynch Controller di una delle risposte mi ha fatto riflettere. Quando ho scoperto che ho dovuto cambiare quanto segue per il vecchio metodo MVC2 a lavorare:

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

Quando ho guardato il metodo TransferRequest ho trovato che 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)

Inoltre v'è un essere Eccezione gettato prima dell'eccezione che ho postato (mi sono semplicemente perso perché ho fatto tardi l'eccezione). Questa eccezione è:

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) 

Così come faccio a fare questo lavoro?

+2

Bene, vediamo se posso dedurre questo psychicly ... ... ... umm .. no .. si sta andando ad avere per fornire un certo codice. Quali intestazioni stai aggiungendo e quando? –

+1

Forse questo aiuterà: http://stackoverflow.com/questions/2383169/server-cannot-set-status-after-http-headers-have-been-sent-iis7-5 –

+1

@Mystere Man: Questo è esattamente il punto. Non aggiungo intestazioni personali, sembra che il passaggio da MVC2 a MVC3 abbia creato questo problema poiché il codice funziona correttamente senza eccezioni in MVC2. Se si guarda nello stacktrace si nota: 'su System.Web.Mvc.MvcHandler.AddVersionHeader (HttpContextBase httpContext)' il che significa che MVC stesso sta cercando di aggiungere un'intestazione, ma non può. Ho provato la soluzione della domanda che mi hai collegato con 'reponse.BufferOutput = true' ma non funziona. Ricevo sempre questa eccezione e stacktrace. – IvanL

risposta

2

Buone notizie, oggi ho risolto il mio problema dopo una ricerca più approfondita sulla causa delle eccezioni. Il primo collegamento che mi ha aiutato a capire che cosa esattamente potrebbe essere la causa delle mie eccezioni ed errori è stato il seguente: http://www.eggheadcafe.com/tutorials/asp-net/79c73563-408a-493e-a369-d4b380bce549/aspnet-using-servertransferrequest.aspx

Descrive il funzionamento di Server.TransferRequest e cita l'avvertenza più importante: la sessione deve essere rilasciata dalla richiesta principale prima di trasferire alla richiesta figlio. Scavando più in profondità come farei questo con MVC mi sono imbattuto nel seguente post qui su StackOverflow: How to simulate Server.Transfer in ASP.NET MVC?

Questo post a sua volta mi ha segnalato una questione estremamente importante sapere: throw new ApplicationException("TempData won't work with Server.TransferRequest!"); così ho creato la classe TransferResult che si può trovare in quel post e lasciare che le azioni che lo richiedevano ritornassero da quel punto. Ho scoperto ora che questa eccezione veniva colpita nei casi specifici che ho menzionato prima. Io stesso non ho mai usato TempData, ma a quanto pare uno dei miei colleghi ha fatto.

A causa della natura dei dati non importanti all'interno ho deciso di Clear() il TempData prima di qualsiasi Server.TransferRequest() che ha reso le mie eccezioni e problemi sciogliersi come neve al sole.

Desidero ringraziare tutte le persone che hanno cercato di risolvere questo problema e sono lieto di poter fornire una conclusione e una soluzione conclusive in modo che possano beneficiare coloro che stanno osservando lo stesso problema.

Cordiali saluti, IvanL

+0

Sai perché dobbiamo verificare i dati in TempData prima di chiamare TransferRequest? – yurart

+1

@yurart Come menzionato sopra, lo stato della sessione deve essere rilasciato e tempdata sembra "bloccare" la sessione, rendendo impossibile trasferire la richiesta. – IvanL

+0

grazie per la risposta – yurart

2

Ciò può accadere se il buffer è stato disattivato nella pagina. Buffering significa che asp.net attende che l'intera richiesta venga completata prima di inviare la risposta. Ciò significa che l'intestazione può essere modificata in qualsiasi momento. Quando il buffering è disattivato, l'output viene inviato al client non appena viene generato. Pertanto, non è possibile modificare le intestazioni a piacere, poiché sono già state inviate.

Dal tuo stacktrace, sembra essere un controller asincrono & Mi chiedo se questo ha qualcosa a che fare con esso. Sto solo supponendo da quello che hai postato però.

Aggiornamento

correzione, la menzione asincrona è in realtà codice del framework & nulla a che fare con il codice. Tuttavia dal tuo codice sopra, è SearchResultOverview un'azione su un controller? Se è così, allora usando i metodi che stai usando per trasferire l'esecuzione penso che sia la causa dei tuoi problemi.

Ciò causa 2 mvchandlers per l'esecuzione di & che interferiscono l'uno con l'altro. Il routing sarebbe un modo migliore per reindirizzare la richiesta.

+0

Mi riferirò al commento che ho scritto in risposta a Mystere Man. Ho provato ad abilitare il buffering in BeginRequest ma non ha cambiato nulla. Cosa cambia tra MVC2 e MVC3 che le intestazioni improvvise vengono inviate in precedenza e devo iniziare a cambiare i comportamenti come il buffering? Dici che sembra essere un controller asincrono ma quel concetto non esisteva in MVC2 per quanto ne so io e questo è puramente un progetto che è stato aggiornato da MVC2 a MVC3 usando lo strumento di aggiornamento da codeplex scritto dall'ASP. Squadra NET. – IvanL

+0

In effetti, mi sbagliavo sul asincrono. MVC 3 gestisce tutto attraverso questo. Sarebbe una cosa di struttura, non il tuo codice. I –

0

Mi ricordo di aver avuto questo problema qualche tempo fa. Non ricordo le condizioni esatte, ma aveva qualcosa a che fare con l'impostazione delle intestazioni e del codice di stato http direttamente all'interno di un filtro azioni personalizzato.

Il mio obiettivo era quindi quello di mostrare una pagina/messaggio personalizzato quando l'autenticazione utente è scaduta e cliccato su un collegamento azione Ajax (come quando lascia la pagina aperta per un po ', poi torna e fa clic sul link) , così asp.net mvc non ha mostrato la pagina di login predefinita all'interno di un div (un po 'brutto). Non ho il codice a portata di mano in questo momento, ma era qualcosa di simile:

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

Il fatto è, provare questo stesso codice su una versione precedente di asp.net mvc mi ha dato il "non può accodare intestazione "errore. Non ricordo come l'ho risolto, ma non è stato comunque facile. Posso cercare tra i miei vecchi progetti per il codice fisso se pensi che questo caso si applichi a te.

Speranza che aiuta

+0

Cura di dire perché il downvote? Forse questo non si applica al problema esatto che il richiedente ha avuto, ma può aiutare le altre persone. Accidenti ... – Francisco

+0

Sto affrontando lo stesso problema. L'unica differenza è che ho la logica in OnActionExecuted. Ti dispiacerebbe condividere la correzione? –

+0

Non ce l'ho, è perso nel tempo ... ma la parte fondamentale è impostare direttamente il risultato, come questo ad esempio: filterContext.Result = new HttpUnauthorizedResult(); – Francisco

Problemi correlati