Выходной поток HttpWebResponse не закрывается - PullRequest
2 голосов
/ 11 января 2012

Я пишу пользовательский ActionFilterAttribute и пытаюсь записать некоторые данные непосредственно в выходной поток в ASP.NET MVC 3. Все, что я пишу, - это все, что мне нужно, чтобы получить ответ, но после записи естьдополнительные данные после моих данных - представленный вид.Я пытаюсь закрыть OutputStream, но он все еще остается доступным для записи.Как я могу закрыть этот поток для записи или игнорировать следующий рендеринг HTML?

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
    var request = filterContext.RequestContext.HttpContext.Request;
    var acceptTypes = request.AcceptTypes ?? new string[] {};
    var response = filterContext.HttpContext.Response;

    if (acceptTypes.Contains("application/json"))
    {
        response.ContentType = "application/json";
        Serializer.Serialize(data, response.ContentType, response.OutputStream);
    }
    else if (acceptTypes.Contains("text/xml"))
    {
        response.ContentType = "text/xml";
        Serializer.Serialize(data, response.ContentType, response.OutputStream);
    }
    response.OutputStream.Close();
}  

UPD
Например, мои данные {"Total": 42, "Now": 9000}
И мой взгляд такой

<div>
    <span>The data that shouldn't be here</span>
</div>

В ответ я получаю

{"Total": 42, "Now": 9000}
<div>
    <span>The data that shouldn't be here</span>
</div>

, и это не является действительным JSON, как вы можете видеть.Моя цель - отправить только JSON или XML

Ответы [ 2 ]

1 голос
/ 12 января 2012

После большого количества усилий я нашел решение, которое соответствует моим требованиям.Это было на вершине проблемы.Все, что мне нужно, это очистить ответ перед закрытием.Но в этом случае Content-Length HTTP-заголовок пропущен, а длина содержимого записана прямо в тело ответа.Поэтому нам нужно просто установить этот заголовок вручную перед сбросом ответа.

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
    var request = filterContext.RequestContext.HttpContext.Request;
    var acceptTypes = request.AcceptTypes ?? new string[] {};
    var response = filterContext.HttpContext.Response;

    if (acceptTypes.Contains("application/json"))
    {
        WriteToResponse(filterContext, data, response, "application/json");
    }
    else if (acceptTypes.Contains("text/xml"))
    {
        WriteToResponse(filterContext, data, response, "text/xml");
    }
}

private void WriteToResponse(ActionExecutedContext filterContext, object data, HttpResponseBase response, String contentType)
{
    response.ClearContent();
        response.ContentType = contentType;
        var length = Serializer.Serialize(data, response.ContentType, response.OutputStream);
        response.AddHeader("Content-Length", length.ToString());
        response.Flush();
        response.Close();
}

Поток записывается в него с помощью Serializer.Serialize, и этот метод также возвращает длину содержимого, записанного в выходной поток.

1 голос
/ 11 января 2012

Конвейер ASP.NET управляет жизненным циклом объекта ответа.Если вы должны были внезапно закрыть поток или завершить ответ, компоненты, находящиеся ниже по потоку, потерпят неудачу при попытке записи.

Если вы хотите заставить систему завершить ответ, вы должны вызвать HttpApplication.CompleteRequest().Он пропустит остальные события в конвейере ASP.NET, поэтому он не без потенциально нежелательных побочных эффектов, но это рекомендуемый подход.

Более подробную информацию можно найти здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...