Реализовать отправку событий, отправленных сервером, в C # (без ASP.NET / MVC /…)

2

Для проекта мне нужно реализовать SSE (события, отправленные сервером) в приложении С#. Хотя это может показаться легким, я не знаю, как это решить.

Поскольку я новичок в С# (хотя и не новичок в программировании в целом), я совершил экскурсию в Google и попытался найти какой-то образец кода. Из того, что я видел до сих пор, я мог бы научиться создавать HTTP-сервер с С# или потреблять события, отправленные сервером. Но я ничего не нашел о отправке SSE.

Я пытаюсь разобраться: как я могу продолжать отправлять обновленные данные по входящему запросу? Обычно вы получаете запрос, делаете свое дело и отвечаете. Выполнено, соединение закрыто. Но в этом случае я хочу "прилипать" к потоку ответов и отправлять новые данные, каждый раз, когда запускается событие в моем приложении.

Проблема, для меня, заключается в этом основанном на событиях подходе: это не какой-то опрос и обновление на основе intervall. Скорее, это приложение похоже на "Эй, что-то случилось. Я действительно должен рассказать вам об этом!"

TL; DR: как я могу поддерживать этот поток ответов и отправлять обновления - не на основе циклов или таймеров, но каждый раз, когда срабатывают определенные события?

Кроме того, прежде чем я забуду: я знаю, есть библиотеки, которые делают именно это. Но из того, что я видел до сих пор (и из того, что я понял, исправьте меня, если я ошибаюсь), эти решения зависят от ASP.NET/MVC/вы называете это. И поскольку я просто пишу "простое" приложение С#, я не думаю, что отвечаю этим требованиям.

  • 0
    Нет, есть библиотеки, которые не требуют ASP.NET. Просто исследования для них. Даже если у них есть имя ASP.NET, это может быть связано с тем, что они работают в команде ASP.NET и могут быть размещены самостоятельно. Я бы не стал ограничиваться и SSE, не забывайте о таких технологиях, как веб-сокеты.
  • 0
    Я не сомневаюсь в этом. Я просто говорю, что из того, что я видел до сих пор, я не смог найти ничего. Для меня результаты до сих пор были либо о клиентах SSE, либо, если нет, о ASP.NET. Как вы, вероятно, можете себе представить, поиск «серверной библиотеки событий на стороне сервера» довольно бесполезен. Но если вы можете предоставить мне ссылку на библиотеку, я с радостью возьму ее. :)
Показать ещё 11 комментариев
Теги:
server-sent-events

2 ответа

2
Лучший ответ

Это звучит неплохо для SignalR. Примечание. SignalR является частью семейства ASP.NET, однако для этого не требуется инфраструктура ASP.NET(System.Web) или IIS, как указано в комментариях.

Чтобы уточнить, SignalR является частью ASP.NET. Согласно их сайту:

ASP.NET - это веб-платформа с открытым исходным кодом для создания современных веб-приложений и сервисов с.NET. ASP.NET создает веб-сайты на основе HTML5, CSS и JavaScript, которые являются простыми, быстрыми и могут масштабироваться для миллионов пользователей.

SignalR не имеет жесткой зависимости от System.Web или IIS.

Вы можете самостоятельно разместить приложение ASP.Net (см. Https://docs.microsoft.com/en-us/aspnet/signalr/overview/deployment/tutorial-signalr-self-host). Если вы используете ядро .net, оно фактически самообслуживается по умолчанию и работает как обычное консольное приложение.

  • 0
    Я уже наткнулся на эту библиотеку, но часть ASP.NET удержала меня. Судя по документам, на которые вы ссылались, я задаюсь вопросом: кажется, что нет специфичной для консольного приложения части, верно? Так что я мог бы просто включить это в свой плагин VSTO? Или это приведет к проблемам с точки зрения потоков (т. Е. Сервер блокирует дальнейший путь кода)?
  • 0
    эм ... технически SignalR является частью asp.net. Кажется, немного вводит в заблуждение, что он не требует этого - это похоже на то, что веб-формы не требуют Asp.Net. Может быть, мы просто определяем «Asp.net» немного по-другому?
Показать ещё 3 комментария
3

Что касается облегченного сервера, я бы выбрал собственный веб-интерфейс OWIN (https://docs.microsoft.com/en-us/aspnet/web-api/overview/hosting-aspnet-web-api/use-owin- сам-хост-веб-API).

Простое действие сервера событий, отправляемое сервером, в основном будет выглядеть так:

public class EventController : ApiController
  {
    public HttpResponseMessage GetEvents(CancellationToken clientDisconnectToken)
    {
      var response = Request.CreateResponse();
      response.Content = new PushStreamContent(async (stream, httpContent, transportContext) =>
      {
        using (var writer = new StreamWriter(stream))
        {
          using (var consumer = new BlockingCollection<string>())
          {
            var eventGeneratorTask = EventGeneratorAsync(consumer, clientDisconnectToken);
            foreach (var @event in consumer.GetConsumingEnumerable(clientDisconnectToken))
            {
              await writer.WriteLineAsync("data: " + @event);
              await writer.WriteLineAsync();
              await writer.FlushAsync();
            }
            await eventGeneratorTask;
          }
        }
      }, "text/event-stream");
      return response;
    }

    private async Task EventGeneratorAsync(BlockingCollection<string> producer, CancellationToken cancellationToken)
    {
      try
      {
        while (!cancellationToken.IsCancellationRequested)
        {
          producer.Add(DateTime.Now.ToString(), cancellationToken);
          await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
        }
      }
      finally
      {
        producer.CompleteAdding();
      }
    }
  }

Важной частью здесь является PushStreamContent, который просто отправляет заголовки HTTP, а затем оставляет соединение открытым для записи данных, когда оно доступно.

В моем примере события генерируются в дополнительной задаче, которая получает коллекцию производитель-потребитель и добавляет события (здесь текущее время каждую секунду), если они доступны для коллекции. Всякий раз, когда приходит новое событие, GetConsumingEnumerable автоматически уведомляется. Затем новое событие записывается в правильном формате, отправленном сервером, в поток и сбрасывается. На практике вам нужно было бы отправлять некоторые псевдопинг-события каждую минуту или около того, так как потоки, которые остаются открытыми в течение длительного времени без передачи данных через них, будут закрыты ОС/средой.

Пример кода клиента для проверки этого будет выглядеть так:

Напишите следующий код в асинхронном методе.

using (var client = new HttpClient())
{
  using (var stream = await client.GetStreamAsync("http://localhost:9000/api/event"))
  {
    using (var reader = new StreamReader(stream))
    {
      while (true)
      {
        Console.WriteLine(reader.ReadLine());
      }
    }
  }
}
  • 0
    Почему это вместо SignalR?
  • 0
    @ckuri yours выглядит как идеальный ответ, я хочу использовать отправленные сервером события в настольном приложении C # WPF. Подскажите, пожалуйста, как должен быть реализован код на стороне клиента или слушателя? Спасибо,
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню