ASP.NET MVC 3: сервер не может добавить заголовок после отправки заголовков HTTP - PullRequest
5 голосов
/ 14 декабря 2011

Мы заняты обновлением приложения ASP.NET MVC 2 с использованием платформы 3.5 до приложения ASP.NET MVC 3, работающего на среде 4.0.

Есть страница, которая выдает исключение при приближении с помощью кнопки возврата браузера. Для поддержки кнопки возврата браузера на этой странице мы внедрили систему, которая запрашивает результаты для этой страницы заново при возвращении на страницу. У меня нет четких указаний, где искать проблему, так как я всегда нахожу только ошибку

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

EDIT: Я добавляю новую информацию и понимание, которое я получил, охотясь за этой проблемой. Упоминание Asynch Controller об одном из ответов заставило меня задуматься. Когда я обнаружил, что для работы старого метода 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)

Так как мне заставить это работать?

Ответы [ 3 ]

2 голосов
/ 22 декабря 2011

Хорошая новость, сегодня я решил собственную проблему после более тщательного исследования причины исключений.Первая ссылка, которая помогла мне понять, что именно может быть причиной моих исключений и ошибок, была следующей: http://www.eggheadcafe.com/tutorials/asp-net/79c73563-408a-493e-a369-d4b380bce549/aspnet-using-servertransferrequest.aspx

В ней подробно описывается работа Server.TransferRequest и упоминаются все важные предостережения: Сессия должна быть освобожденапо основному запросу перед передачей ребенку запроса.Углубившись в то, как я это сделаю с MVC, я наткнулся на следующий пост здесь на stackoverflow: Как смоделировать Server.Transfer в ASP.NET MVC?

Этот пост, в свою очередь, указал мнена чрезвычайно важный вопрос: throw new ApplicationException("TempData won't work with Server.TransferRequest!"); Итак, я создал класс TransferResult, который можно найти в этом посте, и позволил действиям, которые его требовали, вернуться через эту точку.Теперь я обнаружил, что это исключение применяется в конкретных случаях, о которых я упоминал ранее.Я сам никогда не использовал TempData, но, видимо, один из моих коллег использовал.

Из-за характера неважных данных внутри я решил Clear() TempData до любых Server.TransferRequest(), из-за которых мои исключения и проблемы таяли как снегна солнце.

Я хочу поблагодарить всех людей, которые искали решение этой проблемы, и я рад, что могу предоставить заключительное заключение и решение, чтобы оно могло принести пользу тем, кто смотрит на ту же проблему.

С уважением, IvanL

2 голосов
/ 14 декабря 2011

Это может произойти, если на странице отключена буферизация.Буферизация означает, что asp.net ожидает завершения всего запроса перед отправкой ответа.Это означает, что заголовок может быть изменен в любое время.Когда буферизация отключена, выходные данные отправляются клиенту по мере его создания.Поэтому вы не можете изменять заголовки по своему желанию, так как они уже были отправлены.

Из вашей трассировки стека это похоже на асинхронный контроллер, и мне интересно, имеет ли это какое-либо отношение к этому.Я только догадываюсь из того, что вы опубликовали.

Обновление

Исправление, асинхронное упоминание на самом деле является фреймворковым кодом и не имеет ничего общего с вашим кодом.Однако из вашего кода выше, SearchResultOverview является действием на контроллере?Если так, то использование методов, которые вы используете для передачи выполнения, - это, я думаю, причина ваших проблем.

Это приводит к тому, что 2 mvchandler запускаются, и они мешают друг другу.Маршрутизация была бы лучшим способом перенаправить запрос.

0 голосов
/ 15 декабря 2011

Я помню, как однажды столкнулся с этой проблемой.Я не помню точных условий, но это было как-то связано с установкой заголовков и кода состояния 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 дала мне «не можетдобавить заголовок "ошибка.Я не помню, как я это исправил, но все равно это было нелегко.Я могу искать в своих старых проектах исправленный код, если вы считаете, что этот случай относится к вам.

Надеюсь, это поможет

...