2011-12-14 19 views
5

Jesteśmy zajęci aktualizacją aplikacji ASP.NET MVC 2 przy użyciu frameworka 3.5 do aplikacji ASP.NET MVC 3 działającej w środowisku 4.0.ASP.NET MVC 3: Serwer nie może dołączyć nagłówka po wysłaniu nagłówków HTTP

Istnieje strona, która zgłasza wyjątek po zbliżeniu za pomocą przycisku Wstecz przeglądarki. Aby obsłużyć przycisk wstecz przeglądarki na tej stronie, zaimplementowaliśmy system, który odsyła wyniki na tej stronie od nowa po powrocie na stronę. I nie mają wyraźnego wskazania, gdzie szukać problemu jednak od zawsze tylko znaleźć błąd

Server cannot append header after HTTP headers have been sent. 

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

Jak to nagłówki HTTP już zostały wysłane?

Dziękuję z góry, IvanL

EDIT: dodaję nowe informacje i wgląd otrzymałem podczas polowania na ten problem. Administrator Asynch wspomina o jednej z odpowiedzi, która mnie zastanowiła. Kiedy okazało się, że musiałem zmienić następujące do starej metody MVC2 pracować:

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

kiedy spojrzał metodę TransferRequest odkryłem, że 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)

Ponadto istnieje istota Wyjątek wyrzucony przed wyjątkiem, który napisałem (po prostu przegapiłem go, ponieważ wycofałem się z wyjątku późno). Ten wyjątek to:

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) 

Jak mogę to wykonać?

+2

Cóż, pozwól mi zobaczyć, czy mogę wywnioskować to psychicly ... ... ... hmm .. nope .. będziesz musiał dostarczyć jakiś kod. Jakie nagłówki dodajesz i kiedy? –

+1

Może to pomoże: http://stackoverflow.com/questions/2383169/server-cannot-set-status-after-http-headers-have-been-sent-iis7-5 –

+1

@Mystere Man: Właśnie o to chodzi. Sam nie dołączam żadnych nagłówków, wydaje się, że zmiana z MVC2 na MVC3 stworzyła ten problem, ponieważ kod działa poprawnie bez żadnych wyjątków w MVC2. Jeśli spojrzysz na stacktrace, zauważysz: 'w System.Web.Mvc.MvcHandler.AddVersionHeader (HttpContextBase httpContext)' co oznacza, że ​​MVC próbuje dodać nagłówek, ale nie może tego zrobić. Próbowałem rozwiązać pytanie, które łączyłeś mnie z 'reponse.BufferOutput = true', ale to nie działa. Zawsze otrzymuję ten wyjątek i stacktrace. – IvanL

Odpowiedz

2

Dobre wieści, dzisiaj rozwiązać własne problemy po bardziej dokładnych badań na temat przyczyn wyjątków. Pierwszy link, który pomógł mi zrozumieć, co dokładnie może być przyczyną moich wyjątków i błędów, był następujący: http://www.eggheadcafe.com/tutorials/asp-net/79c73563-408a-493e-a369-d4b380bce549/aspnet-using-servertransferrequest.aspx

Szczegóły działania Server.TransferRequest i wspomina o wszystkich ważnych zastrzeżeniach: Sesja musi zostać zwolniona przez główne żądanie przed przeniesieniem do wniosku dziecka. Kopania głębiej w jaki sposób mogę to zrobić z MVC natknąłem poniższej post tutaj na stackoverflow: How to simulate Server.Transfer in ASP.NET MVC?

Ten post z kolei wskazał mi do niezwykle ważnej sprawie wiedzieć: throw new ApplicationException("TempData won't work with Server.TransferRequest!"); Więc stworzyłem klasę TransferResult które można znaleźć w tym poście i pozwól, aby żądane działania powróciły za pośrednictwem tego punktu. Zauważyłem, że ten wyjątek został trafiony w konkretnych przypadkach, o których wspomniałem wcześniej. Ja sam nigdy nie użyłem TempData, ale podobno tak zrobił jeden z moich kolegów.

Ze względu na naturę nieistotnych danych w środku zdecydowałem się na Clear() TempData przed jakimkolwiek Server.TransferRequest(), dzięki czemu moje wyjątki i problemy stopiły się jak śnieg na słońce.

Chciałbym podziękować wszystkim, którzy chcieli rozwiązać ten problem i cieszę się, że mogę przedstawić końcowe rozwiązanie i rozwiązanie, które może przynieść korzyści tym, którzy patrzą na ten sam problem.

poważaniem IvanL

+0

Czy wiesz, dlaczego musimy sprawdzić dane w TempData przed wywołaniem TransferRequest? – yurart

+1

@yurart Jak wspomniano powyżej, stan sesji musi zostać zwolniony, a tempdata wydaje się "blokować" sesję, co uniemożliwia przeniesienie żądania. – IvanL

+0

dzięki za odpowiedź – yurart

2

Może się to zdarzyć, jeśli buforowanie zostało wyłączone na stronie. Buforowanie oznacza, że ​​asp.net czeka na zakończenie całego żądania przed wysłaniem odpowiedzi. Oznacza to, że nagłówek można zmienić w dowolnym momencie. Gdy buforowanie jest wyłączone, dane wyjściowe są wysyłane do klienta podczas jego generowania. Dlatego nie możesz zmienić nagłówków zgodnie z wolą użytkownika, ponieważ zostały już wysłane.

Z twojego stacktrace wydaje się być kontrolerem asynchronicznym. & Zastanawiam się, czy to ma z tym coś wspólnego. Zgaduję tylko z tego, co napisałeś.

Aktualizacja

Correction, wzmianka asynchroniczny jest rzeczywiście code Akty & nic wspólnego z kodem. Jednak z powyższego kodu jest SearchResultOverview działanie na kontroler? Jeśli tak, to używając metod, których używasz do transferu wykonania, myślę, że przyczyną twoich problemów.

Powoduje to, że 2 urządzenia mvchandlers wykonują &, co powoduje wzajemne zakłócenia. Routing byłby lepszym sposobem na przekierowanie żądania.

+0

Odniosę się do komentarza, który napisałem w odpowiedzi na Mystere Man. Próbowałem włączyć buforowanie w BeginRequest, ale nic nie zmieniło. Jakie zmiany między MVC2 i MVC3, że nagłe nagłówki są wysyłane wcześniej i muszę zacząć zmieniać zachowania, takie jak buforowanie? Mówisz, że wydaje się być kontrolerem asynchronicznym, ale ta koncepcja nie istniała w MVC2, o ile mi wiadomo, a to jest czysto projekt, który został uaktualniony z MVC2 do MVC3 przy użyciu narzędzia aktualizacji z codeplex napisanego przez ASP. Zespół NET. – IvanL

+0

Rzeczywiście, myliłem się co do asynchronizacji. MVC 3 obsługuje wszystko przez to. To byłaby struktura, a nie twój kod. I –

0

Pamiętam, że miałem ten problem jakiś czas temu. Nie pamiętam dokładnie warunków, ale miało to coś wspólnego z ustawianiem nagłówków i kodu statusu HTTP bezpośrednio w niestandardowym filtrze akcji.

Moim celem było wówczas pokazanie niestandardowej strony/wiadomości, gdy autoryzacja użytkownika przekroczyła limit czasu i kliknęła link akcji ajax (np. Gdy pozostawia otwartą stronę przez jakiś czas, a następnie wraca i klika łącze) , więc asp.net mvc nie pokazał domyślnej strony logowania wewnątrz div (rodzaj brzydkiego). Nie mam kodu pod ręką teraz, ale to było coś takiego:

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

Chodzi o to, próbując tego samego kodu na wcześniejszej wersji programu ASP.NET MVC dał mi „nie może dołączyć nagłówek "błąd. Nie pamiętam, jak to naprawiłem, ale i tak nie było łatwo. Mogę przeszukiwać moje stare projekty dla ustalonego kodu, jeśli uważasz, że ten przypadek dotyczy ciebie.

Nadzieja pomaga

+0

Dbasz, aby powiedzieć, dlaczego spadł? Może to nie dotyczy dokładnie problemu, który miał pytający, ale może pomóc innym. Geez ... – Francisco

+0

Mam do czynienia z tym samym problemem. Jedyna różnica polega na tym, że mam logikę w OnActionExecuted. Czy mógłbyś podzielić się poprawką? –

+0

Nie mam go, jest zagubiony w czasie ... ale kluczową częścią jest ustawienie wyniku bezpośrednio, na przykład: filterContext.Result = new HttpUnauthorizedResult(); – Francisco

Powiązane problemy