Как создать маршрут GET, действующий как маршрут подписки

#c# #asp.net-web-api #.net-core #asp.net-core-webapi #.net-5

Вопрос:

У меня есть веб-API .Net 5, и я хотел бы создать GET конечную точку (действующую как подписка), отправляющую данные каждые x секунд. Я знаю, что там есть инструменты, например, SignalR, но я хотел бы знать, можно ли достичь того же результата с помощью простого маршрута. Может быть, ручей мог бы помочь …

Это мой пример контроллера

 [ApiController]
[Route("[controller]")]
public class MyController : ControllerBase
{
    [HttpGet]
    public OkResult SendDataEvery5Seconds()
    {
        return Ok(); // send back an initial response

        // send data every 5 seconds
    }
}
 

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

 const express = require('express')
const app = express()

app.get('/', (req, res) => {
  res.writeHead(200, {
      'content-type': 'application/x-ndjson'
  });

  setInterval(() => {
      res.write(JSON.stringify(new Date())   'n');
  }, 5000);
})

app.listen(3000);
 

запуск curl -i http://localhost:3000 должен записывать дату каждые 5 секунд.

Комментарии:

1. У вашего контроллера есть Response свойство, с помощью которого вы можете отправлять данные ответа вручную. ( Response.Body ).

2. Попробуйте записать цикл while с помощью thread.sleep и записать данные в ответ. while (true) { Thread.Sleep(5000); return Ok();}

3. Это истощит ваш сервер, так как метод будет продолжать работать даже при закрытии клиента.

Ответ №1:

Вы можете сделать это вот так.

Код сервера:

 [HttpGet]
public async Task Get(CancellationToken ct = default)
{
    Response.StatusCode = 200;
    Response.Headers["Content-Type"] = "application/x-ndjson";

    // you can manage headers of the request only before this line
    await Response.StartAsync(ct);

    
    // cancellation token is important, or else your server will continue it's work after client has disconnected
    while (!ct.IsCancellationRequested)
    {
        await Response.Body.WriteAsync(Encoding.UTF8.GetBytes("some data heren"), ct);
        await Response.Body.FlushAsync(ct);

        // change '5000' with whatever delay you need
        await Task.Delay(5000, ct);
    }
}
 

Соответствующий клиентский код (пример c#):

 var client = new HttpClient();

var response = await client.GetStreamAsync("http://localhost:5000/");

using var responseReader = new StreamReader(response);


while (!responseReader.EndOfStream)
{
    Console.WriteLine(await responseReader.ReadLineAsync());
}