基于 SSE、asp.net core razor 实现比分Live

前言

最近在项目中用到了 SSE (Server-Sent Events),用于服务的单向长连接数据推送。因为都是使用 C# 实现的,所以服务端使用的是 HttpListener ,而客户端更简单,只使用了 HttpClient ,连接了之后就一直读流,一旦流读取错误或超时,则尝试重连接。

有感于这种方式简单便捷,便一直一条路走到黑(中间踩了坑),对它进行不断打磨。最后,设计出了一款主打轻量级、兼顾性能、易扩展、开箱即用的纯 C# 实现的 SSE 工具包------ TinyHttpSSE.DotNet ,并已经开源。

简介

TinyHttpSSE.DotNet 在 github 有着详细的介绍,在此仅介绍 SSE。

Server-Sent Events(SSE)是一种基于 HTTP 协议的服务器推送技术,它允许服务器以流的方式向客户端实时推送数据。意味着支持SSE 的浏览器有着对应的支持------EventSource,所以实现 SSE 的 服务端都能与浏览器无缝衔接。

以下,我将基于 TinyHttpSSE.DotNetasp.net core razor 实现一个比分直播的 Demo。

比赛得分Live Demo

  1. 创建项目 asp.net core razor ,添加 nuget 包------ TinyHttpSSE.DotNet.Server
  1. 修改 Program.cs ,设置 HttpSseServer 单例依赖注入,并添加 SseServerHostdService

Program.cs:

复制代码
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddSingleton((service) => {
    var config=service.GetService<IConfiguration>();
    //SseServerUrl:http://+:9111/msg/
    return new HttpSseServer(config.GetValue<string>("SseServerUrl"));
});
builder.Services.AddHostedService<SseServerHostdService>();

builder.Services.AddRazorPages();

var app = builder.Build();

SseServerHostdService.cs:

复制代码
public class SseServerHostdService : IHostedService
{
    private readonly HttpSseServer _server;
    public SseServerHostdService(HttpSseServer httpSseServer) { 
        _server = httpSseServer;
    }
    public async Task StartAsync(CancellationToken cancellationToken) {
        await Task.Run(() => {
            bool result= _server.Start();
        });
    }

    public async Task StopAsync(CancellationToken cancellationToken) {
        await _server.Stopping();
    }
}
  1. 修改 Index.cshtml ,实现 EventSource,成为比分直播页面

Index.cshtml:

复制代码
@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}
@section Scripts{
    <script>
        const eventSource = new EventSource("http://127.0.0.1:9111/msg/");
        eventSource.onmessage = function (event) { 
            if (event.data) {
                //document.getElementById('content').innerHTML += event.data ;
                const status = JSON.parse(event.data);
                document.getElementById('score1').innerHTML = status.score1;
                document.getElementById('score2').innerHTML = status.score2;
                if (status.lastaction) {
                    document.getElementById('content').innerHTML += status.lastaction;
                }
            }
        }
    </script>
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <div style="font-size:40px">
        <p >
            <span id="score1">0</span>
            <span>-</span>
            <span id="score2">0</span>
        </p>
    </div>
    <div id="content" style="width:800px;height:600px;overflow:scroll;">
    </div>
</div>

4.创建 Manage.cshtml 页面,比分输入功能:

Manage.cshtml:

复制代码
@page
@model CompetitionLive.Pages.ManageModel
@{
    
}

<form  method="post">
    <p>
        <label for="number" asp-for="Score1"></label>
        <input type="number" asp-for="Score1" id="score1" />
    </p>
    <p>
        <label for="number" asp-for="Score2"></label>
        <input type="number" asp-for="Score2" />
    </p>
    <p>
        <label for="text2" asp-for="LastAction"></label>
        <input type="text" asp-for="LastAction" />
    </p>
    <p><input type="submit" /></p>
</form>

Manage.cshtml.cs:

复制代码
public class ManageModel : PageModel
{
    private readonly HttpSseServer _httpSseServer;
    public ManageModel( HttpSseServer httpSseServer) {
        _httpSseServer = httpSseServer;
    }
    public int Score1 { get; set; } = 0;
    public int Score2 { get; set; } = 0;
    public string LastAction { get; set; }
    public void OnGet()
    {
       
    }

    public void OnPost(int score1,int score2,string lastAction) {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        dict["score1"] = score1;
        dict["score2"] = score2;
        dict["lastaction"] = lastAction+"<br />";
        
        _httpSseServer.StreamManagement.All.PushSseMsg(Newtonsoft.Json.JsonConvert.SerializeObject(dict));
    }
}

5.启动运行

效果:

附源码地址:TinyHttpSSE.Dotnet.Demo\CompetitionLive