最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

.NET8使用SignalR實現(xiàn)實時通信的完整指南

 更新時間:2025年12月31日 09:19:42   作者:幌才_loong  
SignalR 是一個強大的實時通信庫,能夠在服務器和客戶端之間建立雙向通信,本文將詳細介紹如何在 .NET 8 中使用 SignalR并深入探討 SignalR 在使用通信技術的順序

SignalR 是一個強大的實時通信庫,能夠在服務器和客戶端之間建立雙向通信。本文將詳細介紹如何在 .NET 8 中使用 SignalR,包括服務端配置、CORS 設置、前端調(diào)用以及 WinForms 客戶端實現(xiàn),并深入探討 SignalR 在使用通信技術的順序:WebSocket -> Server-Sent Events (SSE)。

一、服務端實現(xiàn)

1. 安裝 SignalR 包

在項目中安裝 SignalR 核心包:

dotnet add package Microsoft.AspNetCore.SignalR

2. 配置 SignalR 與 CORS

由于 SignalR 可能涉及跨域請求,需要在 Program.cs 中配置 CORS:

var builder = WebApplication.CreateBuilder(args);

// 添加 SignalR 服務
builder.Services.AddSignalR();

// 配置 CORS
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAll", policy =>
    {
        policy.WithOrigins("https://localhost:7100") // 允許的前端地址
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials(); // 允許攜帶認證信息(SignalR 必需)
    });
});

var app = builder.Build();

// 使用 CORS
app.UseCors("AllowAll");

// 映射 SignalR Hub
app.MapHub<ChatHub>("/chatHub");

app.Run();

3. 創(chuàng)建 Hub 類

創(chuàng)建一個繼承自 Hub 的類來處理客戶端連接和消息:

using Microsoft.AspNetCore.SignalR;
using System.Collections.Concurrent;

namespace SignalRDemo;

public class ChatHub : Hub
{
    // 存儲用戶與連接ID的映射
    private static readonly ConcurrentDictionary<string, string> _userConnections = new();
    // 存儲群組與連接ID的映射
    private static readonly ConcurrentDictionary<string, HashSet<string>> _groupConnections = new();

    /// <summary>
    /// 客戶端連接時觸發(fā)
    /// </summary>
    public override async Task OnConnectedAsync()
    {
        Console.WriteLine($"客戶端 {Context.ConnectionId} 已連接");
        await base.OnConnectedAsync();
    }

    /// <summary>
    /// 客戶端斷開連接時觸發(fā)
    /// </summary>
    public override async Task OnDisconnectedAsync(Exception? exception)
    {
        Console.WriteLine($"客戶端 {Context.ConnectionId} 已斷開連接");

        // 從用戶映射中移除
        var user = _userConnections.FirstOrDefault(kv => kv.Value == Context.ConnectionId).Key;
        if (!string.IsNullOrEmpty(user))
        {
            _userConnections.TryRemove(user, out _);
        }

        // 從所有群組中移除
        foreach (var group in _groupConnections.Keys)
        {
            _groupConnections[group].Remove(Context.ConnectionId);
        }

        await base.OnDisconnectedAsync(exception);
    }

    /// <summary>
    /// 用戶登錄(綁定用戶名和連接ID)
    /// </summary>
    public async Task Login(string username)
    {
        _userConnections[username] = Context.ConnectionId;
        await Clients.Caller.SendAsync("LoginSuccess", $"你已登錄為 {username}");
    }

    /// <summary>
    /// 加入群組
    /// </summary>
    public async Task JoinGroup(string groupName)
    {
        if (!_groupConnections.ContainsKey(groupName))
        {
            _groupConnections[groupName] = new HashSet<string>();
        }
        _groupConnections[groupName].Add(Context.ConnectionId);

        await Clients.Caller.SendAsync("JoinGroupSuccess", $"你已加入群組 {groupName}");
    }

    /// <summary>
    /// 發(fā)送消息給所有人
    /// </summary>
    public async Task SendMessageToAll(string user, string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }

    /// <summary>
    /// 發(fā)送消息給單個人
    /// </summary>
    public async Task SendMessageToUser(string targetUser, string user, string message)
    {
        if (_userConnections.TryGetValue(targetUser, out var connectionId))
        {
            await Clients.Client(connectionId).SendAsync("ReceiveMessage", user, message);
        }
        else
        {
            await Clients.Caller.SendAsync("Error", $"用戶 {targetUser} 不在線");
        }
    }

    /// <summary>
    /// 發(fā)送消息給多個人
    /// </summary>
    public async Task SendMessageToUsers(IReadOnlyList<string> targetUsers, string user, string message)
    {
        var connectionIds = new List<string>();
        foreach (var targetUser in targetUsers)
        {
            if (_userConnections.TryGetValue(targetUser, out var connectionId))
            {
                connectionIds.Add(connectionId);
            }
        }

        if (connectionIds.Any())
        {
            await Clients.Clients(connectionIds).SendAsync("ReceiveMessage", user, message);
        }
        else
        {
            await Clients.Caller.SendAsync("Error", "沒有目標用戶在線");
        }
    }

    /// <summary>
    /// 發(fā)送消息給群組
    /// </summary>
    public async Task SendMessageToGroup(string groupName, string user, string message)
    {
        if (_groupConnections.TryGetValue(groupName, out var connections))
        {
            if (connections.Any())
            {
                await Clients.Clients(connections).SendAsync("ReceiveMessage", user, message);
            }
            else
            {
                await Clients.Caller.SendAsync("Error", $"群組 {groupName} 沒有成員");
            }
        }
        else
        {
            await Clients.Caller.SendAsync("Error", $"群組 {groupName} 不存在");
        }
    }
}

二、前端調(diào)用(瀏覽器)

1. 安裝 SignalR 客戶端

在前端項目中安裝 SignalR 客戶端庫:

npm install @microsoft/signalr

2. 前端代碼示例

創(chuàng)建一個簡單的 HTML 頁面,使用 JavaScript 連接 SignalR:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>SignalR Chat</title>
</head>
<body>
    <input type="text" id="username" placeholder="請輸入用戶名" />
    <button onclick="login()">登錄</button>
    <br />
    <input type="text" id="message" placeholder="請輸入消息" />
    <button onclick="sendToAll()">發(fā)送給所有人</button>
    <button onclick="sendToUser()">發(fā)送給單個人</button>
    <button onclick="sendToGroup()">發(fā)送給群組</button>
    <ul id="messages"></ul>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/7.0.0/signalr.min.js"></script>
    <script>
        let connection;
        let username;

        // 連接 SignalR
        function connect() {
            connection = new signalR.HubConnectionBuilder()
                .withUrl("https://localhost:7138/chatHub") // 后端地址
                .build();

            // 接收消息
            connection.on("ReceiveMessage", (user, message) => {
                const li = document.createElement("li");
                li.textContent = `${user}: ${message}`;
                document.getElementById("messages").appendChild(li);
            });

            // 連接成功事件
            connection.start().then(() => {
                console.log("已連接到 SignalR 服務端");
            }).catch(err => {
                console.error(err.toString());
            });
        }

        // 登錄
        function login() {
            username = document.getElementById("username").value;
            connection.invoke("Login", username).catch(err => {
                console.error(err.toString());
            });
        }

        // 發(fā)送給所有人
        function sendToAll() {
            const message = document.getElementById("message").value;
            connection.invoke("SendMessageToAll", username, message).catch(err => {
                console.error(err.toString());
            });
        }

        // 發(fā)送給單個人
        function sendToUser() {
            const targetUser = prompt("請輸入目標用戶名:");
            const message = document.getElementById("message").value;
            connection.invoke("SendMessageToUser", targetUser, username, message).catch(err => {
                console.error(err.toString());
            });
        }

        // 發(fā)送給群組
        function sendToGroup() {
            const groupName = prompt("請輸入群組名稱:");
            const message = document.getElementById("message").value;
            connection.invoke("SendMessageToGroup", groupName, username, message).catch(err => {
                console.error(err.toString());
            });
        }

        // 頁面加載時連接
        connect();
    </script>
</body>
</html>

三、WinForms 客戶端調(diào)用

1. 安裝 SignalR 客戶端包

dotnet add package Microsoft.AspNetCore.SignalR.Client

2. WinForms 客戶端代碼

在窗體中添加以下控件:

  • TextBox:用于輸入用戶名
  • TextBox:用于輸入消息
  • Button:登錄按鈕
  • Button:發(fā)送給所有人按鈕
  • ListBox:顯示接收的消息

然后編寫代碼:

using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Windows.Forms;

namespace SignalRWinFormsClient;

public partial class Form1 : Form
{
    private HubConnection _connection;
    private string _username;

    public Form1()
    {
        InitializeComponent();
    }

    private async void Form1_Load(object sender, EventArgs e)
    {
        // 連接 SignalR
        _connection = new HubConnectionBuilder()
            .WithUrl("https://localhost:7138/chatHub")
            .Build();

        // 接收消息
        _connection.On<string, string>("ReceiveMessage", (user, message) =>
        {
            Invoke(new Action(() =>
            {
                listBoxMessages.Items.Add($"{user}: {message}");
            }));
        });

        try
        {
            await _connection.StartAsync();
            listBoxMessages.Items.Add("已連接到 SignalR 服務端");
        }
        catch (Exception ex)
        {
            listBoxMessages.Items.Add($"連接失?。簕ex.Message}");
        }
    }

    private async void btnLogin_Click(object sender, EventArgs e)
    {
        _username = txtUsername.Text;
        try
        {
            await _connection.InvokeAsync("Login", _username);
            listBoxMessages.Items.Add($"你已登錄為 {_username}");
        }
        catch (Exception ex)
        {
            listBoxMessages.Items.Add($"登錄失?。簕ex.Message}");
        }
    }

    private async void btnSendToAll_Click(object sender, EventArgs e)
    {
        var message = txtMessage.Text;
        try
        {
            await _connection.InvokeAsync("SendMessageToAll", _username, message);
            txtMessage.Clear();
        }
        catch (Exception ex)
        {
            listBoxMessages.Items.Add($"發(fā)送失敗:{ex.Message}");
        }
    }
}

四、SignalR 通信技術順序

SignalR 在建立連接時,會根據(jù)瀏覽器和服務器的支持情況,自動選擇最佳的通信技術。其順序如下:

1. WebSocket

  • 優(yōu)先級最高,是 SignalR 的首選通信方式。
  • 全雙工通信,性能最好,延遲最低。
  • 適用于大多數(shù)現(xiàn)代瀏覽器(Chrome、Firefox、Edge、Safari 等)。
  • 使用標準的 WebSocket 協(xié)議(ws://wss://)。

2. Server-Sent Events (SSE)

  • 如果 WebSocket 不可用(如瀏覽器不支持或被防火墻阻止),SignalR 會退而求其次使用 SSE。
  • 單向通信,服務器可以實時向客戶端推送數(shù)據(jù),但客戶端無法向服務器推送數(shù)據(jù)。
  • 基于 HTTP 協(xié)議,使用 EventSource API。
  • 適用于需要實時更新但不需要雙向通信的場景。

3. 長輪詢 (Long Polling)

  • 如果 SSE 也不可用,SignalR 會使用長輪詢作為最后的 fallback。
  • 客戶端向服務器發(fā)送一個請求,服務器保持連接打開,直到有數(shù)據(jù)要發(fā)送或超時。
  • 超時后,客戶端會立即發(fā)送一個新的請求。
  • 性能較差,但兼容性最好,適用于所有瀏覽器。

通信技術選擇流程

客戶端發(fā)送一個 HTTP 請求到服務器的 /chatHub/negotiate 端點,獲取可用的通信技術列表。

客戶端按照優(yōu)先級順序嘗試使用這些技術:

  • 首先嘗試 WebSocket。
  • 如果 WebSocket 失敗,嘗試 SSE。
  • 如果 SSE 也失敗,使用長輪詢。

一旦成功建立連接,就使用該技術進行實時通信。

技術對比

技術雙向通信性能兼容性
WebSocket現(xiàn)代瀏覽器
SSE否(服務器到客戶端)大多數(shù)現(xiàn)代瀏覽器
長輪詢所有瀏覽器

五、注意事項

  • CORS 配置:必須在服務端正確配置 CORS,允許客戶端來源并啟用 AllowCredentials。
  • 連接管理:使用 OnConnectedAsyncOnDisconnectedAsync 管理客戶端連接狀態(tài)。
  • 用戶映射:維護用戶與 ConnectionId 的映射,以便實現(xiàn)單人和多人消息發(fā)送。
  • 群組管理:使用 Groups 類或自定義映射管理群組。
  • 錯誤處理:客戶端和服務端都需要處理連接中斷和異常情況。
  • 擴展性:如果需要支持大規(guī)模部署,可以使用 Redis 作為 SignalR 的后端,實現(xiàn)多服務器之間的消息共享。

通過本文的指南,你可以快速在 .NET 8 中使用 SignalR 實現(xiàn)實時通信,并支持多種消息發(fā)送方式。無論是前端瀏覽器還是 WinForms 客戶端,都能輕松接入 SignalR 服務。

以上就是.NET8使用SignalR實現(xiàn)實時通信的完整指南的詳細內(nèi)容,更多關于.NET8 SignalR實時通信的資料請關注腳本之家其它相關文章!

相關文章

  • ajax.net對數(shù)據(jù)庫的插入實例

    ajax.net對數(shù)據(jù)庫的插入實例

    ajax.net對數(shù)據(jù)庫的插入實例,需要的朋友可以參考一下
    2013-04-04
  • VS2015下簡單使用EF框架的方法

    VS2015下簡單使用EF框架的方法

    這篇文章主要為大家詳細介紹了VS2015下簡單使用EF框架的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Asp.net中UpdatePanel的用法詳解

    Asp.net中UpdatePanel的用法詳解

    本文詳細的介紹了Asp.net中UpdatePanel的用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-06-06
  • asp.net fileupload 實現(xiàn)上傳

    asp.net fileupload 實現(xiàn)上傳

    在vs的視圖模式下,添加上傳組件,以及添加一個按鈕button,隨后在后置代碼中加入如下信息
    2009-05-05
  • ASP.NET MVC如何使用Unity實現(xiàn)Ioc詳解

    ASP.NET MVC如何使用Unity實現(xiàn)Ioc詳解

    這篇文章主要給大家介紹了關于ASP.NET MVC如何使用Unity實現(xiàn)Ioc的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-07-07
  • asp.net 程序優(yōu)化精選

    asp.net 程序優(yōu)化精選

    對于asp.net需要注意的一些事項,可以提高你的程序運行效率。
    2009-04-04
  • ASP.NET中Web API的簡單實例

    ASP.NET中Web API的簡單實例

    Web API框架是一個面向Http協(xié)議的通信框架,Web API 框架是一個面向Http協(xié)議的通信框架。Web API 框架目前支持兩種數(shù)據(jù)格式的序列化:Json 及 Xml。在不做任何配置的情況下,則 Web API 會自動把數(shù)據(jù)使用xml進行序列化,否則使用 json 序列化,需要的朋友可以參考下
    2015-10-10
  • WPF數(shù)據(jù)驅動修改綁定

    WPF數(shù)據(jù)驅動修改綁定

    這篇文章介紹了WPF數(shù)據(jù)驅動修改綁定的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • ASP.NET 保留文件夾詳解

    ASP.NET 保留文件夾詳解

    在一個ASP.NET應用程序中有許多保留文件夾
    2009-04-04
  • ASP.net與SQLite數(shù)據(jù)庫通過js和ashx交互(連接和操作)

    ASP.net與SQLite數(shù)據(jù)庫通過js和ashx交互(連接和操作)

    這篇文章主要介紹了ASP.net與SQLite數(shù)據(jù)庫通過js和ashx交互(連接和操作),具有一定的參考價值,有興趣的可以了解一下。
    2017-01-01

最新評論

育儿| 邵阳市| 祁东县| 安乡县| 托里县| 突泉县| 丹东市| 遵化市| 漳浦县| 新和县| 东源县| 和静县| 遵化市| 浦江县| 中超| 太原市| 宝鸡市| 门源| 沙坪坝区| 于都县| 拉萨市| 太仓市| 陵川县| 原平市| 东丽区| 邹城市| 隆子县| 宕昌县| 西贡区| 桐庐县| 大方县| 黑水县| 宁远县| 渑池县| 北海市| 鄂伦春自治旗| 利津县| 永兴县| 乌兰县| 海南省| 平果县|