Как работать с ASP.NET Core

Как правильно передать ответ в ASP.NET Core? Существует такой контроллер (ОБНОВЛЕННЫЙ КОД):

[HttpGet("test")]
public async Task GetTest()
{
    HttpContext.Response.ContentType = "text/plain";
    using (var writer = new StreamWriter(HttpContext.Response.Body))
        await writer.WriteLineAsync("Hello World");            
}

Браузеры Firefox/Edge показывают

Hello World

в то время как Chrome/Postman сообщает об ошибке:

Локальная страница не работает

localhost неожиданно закрыл соединение.

ERR_INCOMPLETE_CHUNKED_ENCODING

P.S. Я собираюсь передать много контента, поэтому я не могу заранее указать заголовок Content-Length.

Ответ 1

Чтобы передать ответ, который должен отображаться в браузере, как загруженный файл, вы должны использовать FileStreamResult:

[HttpGet]
public FileStreamResult GetTest()
{
  var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World"));
  return new FileStreamResult(stream, new MediaTypeHeaderValue("text/plain"))
  {
    FileDownloadName = "test.txt"
  };
}

Ответ 2

Можно возвратить null или EmptyResult() (которые эквивалентны), даже если ранее производила запись в Response.Body. Это может быть полезно, если метод возвращает ActionResult чтобы иметь возможность легко использовать все остальные результаты (например, BadQuery()).

[HttpGet("test")]
public ActionResult Test()
{
    Response.StatusCode = 200;
    Response.ContentType = "text/plain";
    using (var sw = new StreamWriter(Response.Body))
    {
        sw.Write("something");
    }
    return null;
}

Ответ 3

Мне также было интересно, как это сделать, и я обнаружил, что исходный код вопроса действительно работает нормально на ASP.NET Core 2.1.0-rc1-final, ни Chrome (и несколько других браузеров), ни приложение JavaScript не перестают работать с такая конечная точка.

Незначительные вещи, которые я хотел бы добавить, это просто установить StatusCode и закрыть поток ответов, чтобы ответ был выполнен:

[HttpGet("test")]
public void Test()
{
    Response.StatusCode = 200;
    Response.ContentType = "text/plain";
    using (Response.Body)
    {
        using (var sw = new StreamWriter(Response.Body))
        {
            sw.Write("Hi there!");
        }
    }
}

Ответ 4

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

[HttpDelete]
public void Content()
{
    Response.StatusCode = 200;
    Response.ContentType = "text/html";

    // the easiest way to implement a streaming response, is to simply flush the stream after every write.
    // If you are writing to the stream asynchronously, you will want to use a Synchronized StreamWriter.
    using (var sw = StreamWriter.Synchronized(new StreamWriter(Response.Body)))
    {
        foreach (var item in new int[] { 1, 2, 3, 4, })
        {
            Thread.Sleep(1000);
            sw.Write($"<p>Hi there {item}!</p>");
            sw.Flush();
        }
    };
}

вы можете проверить с помощью curl с помощью следующей команды: curl -NX DELETE <CONTROLLER_ROUTE>/content

Ответ 5

что-то вроде этого может работать:

[HttpGet]
public async Task<IActionResult> GetTest()
{
    var contentType = "text/plain";
    using (var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World")))
    return new FileStreamResult(stream, contentType);

}