日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

WPF+ASP.NET?SignalR實現后臺通知功能的示例代碼_C#教程

作者:小六公子 ? 更新時間: 2022-11-05 編程語言

在實際業務中,當后臺數據發生變化,客戶端能夠實時的收到通知,而不是由用戶主動的進行頁面刷新才能查看,這將是一個非常人性化的設計。比如數字化大屏,并沒有人工的干預,而是自動的刷新數據,那如何才能實現數據的實時刷新呢?本文以一個簡單示例,簡述如何通過WPF+ASP.NET SignalR實現消息后臺通知以及數據的實時刷新,僅供學習分享使用,如有不足之處,還請指正。

?通過上一篇文章的學習,了解了如何通過SignalR實現在線聊天功能,在示例中,我們發現每一次的客戶端連接都是一個新的實例對象,所以沒有辦法在中心對象中存儲狀態信息,所以為了存儲用戶列表,我們采用了靜態變量的方式。并且在線聊天功能是用戶發送一條消息(Chat),然后觸發中心對象(ChatHub),轉發給另一個用戶(SendAsync)。那么如果實現數字化大屏,需要服務端持續的往客戶端發送消息,而不是客戶端主動觸發,應該怎么做呢?這就是本文需要分享的內容。

涉及知識點

在本示例中,涉及知識點如下所示:

  • 開發工具:Visual Studio 2022 目標框架:.NET6.0
  • ASP.NET SignalR,一個ASP .NET 下的類庫,可以在ASP .NET 的Web項目中實現實時通信,目前新版已支持.NET6.0及以上版本。在本示例中,作為消息通知的服務端。
  • WPF,是微軟推出的基于Windows 的用戶界面框架,主要用于開發客戶端程序。

前提條件

實現服務端持續往客戶端發送消息,除了業務上的需求外,還需要滿足兩個條件:

  • 在服務端有一個常駐內存對象,監聽數據變化。
  • 常駐內存對象,可以訪問中心對象(ChatHub),能夠獲取中心對象的所有連接客戶端,并發送消息。

滿足以上兩個條件,才可以實現想要的功能。

服務端

經過以上分析后,服務端分為兩方面,核心對象(ChatHub),處理業務對象(Worker)。下面我們逐一說明:

ChatHub 中心是用于向連接到 SignalR 服務器的客戶端發送消息的核心抽象,負責客戶端的連接和斷開。如下所示:

using Microsoft.AspNetCore.SignalR;

namespace SignalRChat.Chat
{
    public class ChatHub:Hub
    {
        public override Task OnConnectedAsync()
        {
            Console.WriteLine($"ID:{Context.ConnectionId} 已連接");
            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception? exception)
        {
            Console.WriteLine($"ID:{Context.ConnectionId} 已斷開");
            return base.OnDisconnectedAsync(exception);
        }
    }
}

Worker實例為一個單例對象,常駐內容,實時監聽數據變化,并通過ChatHub上下文(IHubContext<ChatHub>)獲取連接信息,然后發送消息,如下所示:

using Microsoft.AspNetCore.SignalR;

namespace SignalRChat.Chat
{
    public class Worker
    {
        public static Worker Instance;

        private static readonly object locker=new object();

        private IHubContext<ChatHub> context;

        private System.Timers.Timer timer;

        public Worker(IHubContext<ChatHub> context) {
            this.context = context;
            timer= new System.Timers.Timer(500);//單位毫秒
            timer.Enabled=true;
            timer.AutoReset=true;//自動重新
            timer.Elapsed += Timer_Elapsed;
            timer.Start();
        }

        private void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        {
            //模擬數據,一般情況下,從數據庫獲取,然后通知到客戶端
            Dictionary<string, object> data = new Dictionary<string, object>();
            var online = new Random().Next(0, 100);
            var male = Math.Floor(new Random().NextSingle() * online);
            var female = online - male;
            data["online"]=online;
            data["male"] =male;
            data["female"] = female;
            context.Clients.All.SendAsync("Data",data);
        }

        public static void Register(IHubContext<ChatHub> context)
        {
            if (Instance == null)
            {
                lock (locker)
                {
                    if (Instance == null)
                    {
                        Instance = new Worker(context);
                    }
                }
            }
        }
    }
}

注意:此處發送數據的是Data方法,客戶端必須監聽Data方法,才能接收數據。

如何創建單例對象呢,中心對象上下文不能自己創建,必須要和ChatHub通過注入方式的上下文是同一個,不然無法獲取客戶端連接信息。在項目啟動時,通過中間件的方式創建,如下所示:

using Microsoft.AspNetCore.SignalR;
using SignalRChat.Chat;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//1.添加SignalR服務
builder.Services.AddSignalR();
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseRouting();
app.UseHttpsRedirection();

app.UseAuthorization();
//在Use中注冊單例實例
app.Use(async (context, next) =>
{
    var hubContext = context.RequestServices
                            .GetRequiredService<IHubContext<ChatHub>>();
    Worker.Register(hubContext);//調用靜態方法注冊

    if (next != null)
    {
        await next.Invoke();
    }
});
app.MapControllers();
//2.映射路由
app.UseEndpoints(endpoints => {
    endpoints.MapHub<ChatHub>("/chat");
});

app.Run();

客戶端

客戶端主要是連接服務器,然后監聽服務端發送數據的方法即可,如下所示:

namespace SignalRClient
{
    public class ShowDataViewModel : ObservableObject
    {
        #region 屬性及構造函數

        private int online;

        public int Online
        {
            get { return online; }
            set { SetProperty(ref online, value); }
        }

        private int male;

        public int Male
        {
            get { return male; }
            set { SetProperty(ref male, value); }
        }


        private int female;

        public int Female
        {
            get { return female; }
            set { SetProperty(ref female, value); }
        }

        private HubConnection hubConnection;

        public ShowDataViewModel()
        {

        }

        #endregion

        #region 命令

        private ICommand loadedCommand;

        public ICommand LoadedCommand
        {
            get
            {
                if (loadedCommand == null)
                {
                    loadedCommand = new RelayCommand<object>(Loaded);
                }
                return loadedCommand;
            }
        }

        private void Loaded(object obj)
        {
            //1.初始化
            InitInfo();
            //2.監聽
            Listen();
            //3.連接
            Link();
        }

        #endregion

        /// <summary>
        /// 初始化Connection對象
        /// </summary>
        private void InitInfo()
        {
            hubConnection = new HubConnectionBuilder().WithUrl("https://localhost:7149/chat").WithAutomaticReconnect().Build();
            hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(5);
        }

        /// <summary>
        /// 監聽
        /// </summary>
        private void Listen()
        {
            hubConnection.On<Dictionary<string,object>>("Data", ReceiveInfos);
        }

        /// <summary>
        /// 連接
        /// </summary>
        private async void Link()
        {
            try
            {
                await hubConnection.StartAsync();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void ReceiveInfos(Dictionary<string, object> data)
        {
            if (data == null || data.Count < 1)
            {
                return;
            }
            int.TryParse(data["online"]?.ToString(),out int online);
            int.TryParse(data["male"]?.ToString(),out int male);
            int.TryParse(data["female"]?.ToString(),out int female);
            this.Online=online;
            this.Male = male;
            this.Female=female;
        }
    }
}

注意:監聽Data方法,和服務端發送時保持一致。

運行示例

在示例中,需要同時啟動服務端和客戶端,所以以多項目方式啟動,如下所示:

運行成功后,服務端以ASP.NET Web API的方式呈現,如下所示:

客戶端運行如下:

注意:客戶端可以有多個,也可以是一個,后臺通知消息,會通知到每一個連接的客戶端。

原文鏈接:https://www.cnblogs.com/hsiang/p/16687365.html

欄目分類
最近更新