當需要雙向及時通訊,SingalR 則是我的選項之一,它算是非常容易上手的框架。
小朱前輩寫了一些基礎概念的文章,有興趣的可以前往看一下:
https://www.dotblogs.com.tw/regionbbs/Search?q=signalr
開發環境
- VS 2019
- .NET Framework 4.8
- Windows 10
- SignalR 2.4.1
架構
由下圖得知 Client1 發送一個訊息給 SignalR Hub,SignalR Hub 將訊息推播給所有訂閱的 Client
下圖出自:https://www.pubnub.com/learn/glossary/what-is-signalr/
伺服器
安裝套件
Install-Package Microsoft.AspNet.SignalR -version 2.4.1
實作 Hub
BroadcastHub:Hub Name,用戶端訂閱位置
Clients 的成員幾乎都是 dynamic 型別,由這些方法幫我們建立用戶端溝通
Clients.All:通知所有用戶端。
Clients.Clients(ConnectionIds):通知特定用戶端。
ShowMessage:通知有訂閱 ShowMessage 方法的用戶端,對用戶端而言他是 Event Name。
namespace Server.SignalR
{
public class BroadcastHub : Hub
{
public void Broadcast(string name, string country)
{
this.Clients.All.ShowMessage(name, country);
}
}
}
註冊路由
將 Hub 的 Pipeline 注入到 OWIN
[assembly: OwinStartup(typeof(Startup))]
namespace Server
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
取出 Hub
從 OWIN 的 Pipeline 取出 Hub
var context = GlobalHost.ConnectionManager.GetHubContext<BroadcastHub>();
取出 Hub 後,通知有註冊 ShowMessage 方法的用戶端,如下範例:
[HttpPost]
[Route("")]
public IHttpActionResult Post(string name, string country, string connectionIds)
{
var context = GlobalHost.ConnectionManager.GetHubContext<BroadcastHub>();
if (string.IsNullOrWhiteSpace(connectionIds))
{
context.Clients
.All
.ShowMessage(name, country);
}
else
{
//不支援多筆
context.Clients
.Clients(new List<string>
{
connectionIds
})
.ShowMessage(name, country);
}
return new ResponseMessageResult(new HttpResponseMessage(HttpStatusCode.Accepted));
}
當,connectionIds 沒有內容的時候推播給所有的訂閱者,反之,推播特定訂閱者;ConnectionId 則是建立 Hub 後,得到的 Id。
用戶端
安裝套件
Install-Package Microsoft.AspNet.SignalR.Client -version 2.4.1
訂閱通知
HubConnection
:建立連線,傳入服務的位置,當 Hub 建立後可以得到HubConnection.ConnectionId
HubConnection.CreateHubProxy
:建立 Hub,傳入Hub Name,也就是伺服器端的 BroadcastHub
類別
IHubProxy.On
:訂閱,因為在伺服器端寫了 Clients.All.ShowMessage
,ShowMessage
對用戶端而言叫做 Event Name
public partial class Form1 : Form
{
private readonly string _hubName = "BroadcastHub";
private readonly string _signalrUrl = @"https://localhost:44342/";
private readonly HubConnection _hubConnection;
private readonly IHubProxy _hubProxy;
public Form1()
{
this.InitializeComponent();
this._hubConnection = new HubConnection(this._signalrUrl);
this._hubProxy = this._hubConnection.CreateHubProxy(this._hubName);
this._hubProxy.On("ShowMessage",
(string name, string country) =>
{
this.Messages_TextBox
.InvokeIfNecessary(() =>
{
var msg =
$"Hi, My name is {name}, I come from {country}\r\n";
this.Messages_TextBox
.AppendText(msg);
Console.WriteLine(msg);
});
});
this._hubConnection.Start().Wait();
}
}
發送訊息
除了可以接收訊息之外,也可以發訊息
IHubProxy.Invoke:呼叫遠端方法,也就是伺服器端的 BroadcastHub 類別裡的 Broadcast 方法
public partial class Form1 : Form
{
private readonly string _actionName = "Broadcast";
private async void SendMessageButton_Click(object sender, EventArgs e)
{
await this._hubProxy.Invoke(this._actionName,
this.Name_TextBox.Text,
this.Conutry_TextBox.Text);
}
}
範例專案
https://github.com/yaochangyu/sample.dotblog/tree/master/SignalR
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET