“SignalR Self Host+MVC等多端消息推送服务(一)”是一篇介绍使用SignalR实现消息推送服务的教程。它包括了从安装SignalR到在MVC网站上实现消息推送的完整过程。
以下是该教程的详细攻略:
第一步:安装SignalR
在开始之前,我们应该下载并安装SignalR,可以通过NuGet包管理器来安装。使用以下命令来安装:
Install-Package Microsoft.AspNet.SignalR
第二步:创建SignalR Hub类
创建一个Hub类,用于将消息从服务器推送到客户端。可以为此使用Visual Studio的“添加新项”对话框,选择“SignalR Hub Class”模板。例如,如果我们要创建一个名为“ChatHub”的类,可以使用以下代码:
using Microsoft.AspNet.SignalR;
using System.Threading.Tasks;
namespace SignalRChat
{
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
}
在上面的代码中,我们创建了一个名为“SendMessage”的方法,该方法将消息发送到所有连接的客户端。我们还在方法的签名中使用了async和await关键字,以便异步发送广播。
需要注意的是,在SignalR中,方法名称用于标识客户端应调用的方法名称。在上面的代码中,我们使用了“ReceiveMessage”作为客户端应调用的方法名称。
第三步:配置SignalR
要配置SignalR,需要将其添加到Web应用程序的Startup.cs文件中。在ConfigureServices方法中添加以下代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSignalR();
}
接下来,在Configure方法中,添加以下代码:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chatHub");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
在上面的代码中,我们首先使用app.UseRouting()将路由服务添加到管道中,然后使用app.UseEndpoints()将SignalR的终结点和MVC的默认控制器路由添加到管道中。
第四步:调用客户端方法
要从服务器端调用客户端方法,可以在Hub类中包含一个方法,该方法将指定的消息发送到 connected clients。例如,如果我们要使用JavaScript从客户端调用“ReceiveMessage”方法,可以执行以下操作:
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
connection.on("ReceiveMessage", function (user, message) {
console.log(user + " says " + message);
});
connection.start().then(function () {
connection.invoke("SendMessage", "Alice", "Hello");
}).catch(function (err) {
return console.error(err.toString());
});
在上面的代码中,我们首先使用signalR.HubConnectionBuilder()创建连接对象,然后在调用connection.on()方法时,将“ReceiveMessage”方法注册为客户端应接收的方法。最后,我们通过调用connection.invoke()方法来调用服务器上的“SendMessage”方法。在服务器上调用此方法后,客户端上注册的“ReceiveMessage”方法将被调用。
示例说明
示例1:群聊
下面是示例1的完整代码:
using Microsoft.AspNet.SignalR;
using System.Threading.Tasks;
namespace SignalRChat
{
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
}
<!-- Views/Home/Index.cshtml -->
@{
ViewData["Title"] = "Chat Room";
}
<h2>Chat Room</h2>
<input type="text" id="userInput" placeholder="user" />
<input type="text" id="messageInput" placeholder="message" />
<button id="sendButton">Send</button>
<div id="messages">
</div>
@section Scripts
{
<script src="~/lib/signalr/dist/browser/signalr.js"></script>
<script>
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
connection.on("ReceiveMessage", function (user, message) {
var encodedMsg = user + " says " + message;
var li = document.createElement("li");
li.textContent = encodedMsg;
document.getElementById("messages").appendChild(li);
});
document.getElementById("sendButton").addEventListener("click", function (event) {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value;
connection.invoke("SendMessage", user, message).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
connection.start().catch(function (err) {
return console.error(err.toString());
});
</script>
}
在该示例中,我们实现一个简单的聊天室,允许用户输入其名称和消息,然后将消息广播到所有其他连接的客户端。用户在客户端输入名称和消息后,单击“发送”按钮。 将从客户端发送到服务器的消息称为“user”和“message”。 服务器会将此消息发送到所有连接的客户端,并更新消息列表。在客户端上,我们使用connection.invoke()方法调用服务器上的SendMessage方法,并使用on()方法订阅“ReceiveMessage”事件以接收广播消息。
示例2:实时显示股票价格
下面是示例2的完整代码:
using Microsoft.AspNet.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;
namespace SignalRStockTicker
{
public class StockTicker
{
// Singleton instance
private readonly static Lazy<StockTicker> _instance = new(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));
private readonly object _stockPricesLock = new();
private readonly Random _updateOrNotRandom = new();
private readonly Dictionary<string, Stock> _stocks = new();
private readonly Timer _timer;
private StockTicker(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
_stocks = GenerateStocks();
_timer = new Timer
{
Interval = 2000
};
_timer.Elapsed += UpdateStockPrices;
}
private void UpdateStockPrices(object sender, ElapsedEventArgs e)
{
foreach (var stock in _stocks.Values)
{
if (_updateOrNotRandom.NextDouble() > 0.1)
{
// In real life we'd query a database or other data source to get new stock prices.
// Here we'll just manipulate the existing data to make it look like a stock market.
var pos = _updateOrNotRandom.NextDouble() < 0.5 ? 1 : -1;
var change = _updateOrNotRandom.NextDouble() * 2.0; //stock price between -2% and +2%
stock.Price += pos * change * stock.Price;
stock.Price = Math.Round(stock.Price, 2);
// This optional logic makes sure that the price change is no more than 10 percent.
var percentageChange = change * 100 / stock.Price;
if (Math.Abs(percentageChange) > 10)
{
stock.Price -= pos * change * stock.Price;
stock.Price = Math.Round(stock.Price, 2);
}
// Send the new stock price to all clients.
Clients.All.updateStockPrice(stock);
}
}
}
public static StockTicker Instance => _instance.Value;
private IHubConnectionContext<dynamic> Clients { get; set; }
public IEnumerable<Stock> GetAllStocks()
{
return _stocks.Values;
}
private Dictionary<string, Stock> GenerateStocks()
{
return new Dictionary<string, Stock>
{
{ "MSFT", new Stock { Symbol = "MSFT", Price = 200.1m } },
{ "AAPL", new Stock { Symbol = "AAPL", Price = 400.2m } },
{ "GOOG", new Stock { Symbol = "GOOG", Price = 600.3m } },
{ "AMZN", new Stock { Symbol = "AMZN", Price = 800.4m } },
{ "FB", new Stock { Symbol = "FB", Price = 50.5m } }
};
}
public void Start()
{
_timer.Start();
}
public void Stop()
{
_timer.Stop();
}
public Stock GetStock(string symbol)
{
var stock = new Stock { Symbol = "NOT FOUND", Price = 0m };
if (_stocks.ContainsKey(symbol))
{
stock = _stocks[symbol];
}
return stock;
}
}
public class Stock
{
public string Symbol { get; set; }
public decimal Price { get; set; }
}
}
using Microsoft.AspNet.SignalR;
namespace SignalRStockTicker
{
public class StockTickerHub : Hub
{
private readonly StockTicker _stockTicker;
public StockTickerHub() : this(StockTicker.Instance) { }
public StockTickerHub(StockTicker stockTicker)
{
_stockTicker = stockTicker;
}
public void GetAllStocks()
{
var stocks = _stockTicker.GetAllStocks();
Clients.Caller.updateAllStocks(stocks);
}
public void GetStock(string symbol)
{
var stock = _stockTicker.GetStock(symbol);
Clients.Caller.updateStockPrice(stock);
}
}
}
<!-- Views/Home/Index.cshtml -->
@{
ViewData["Title"] = "Stock Ticker";
}
<h2>Stock Ticker</h2>
<div id="stocks-list">
</div>
<div id="stock-price">
</div>
@section Scripts
{
<script src="~/lib/signalr/dist/browser/signalr.js"></script>
<script>
var connection = new signalR.HubConnectionBuilder().withUrl("/stockTickerHub").build();
connection.on("updateAllStocks", function (stocks) {
var table = document.createElement("table");
for (stock of stocks) {
var row = document.createElement("tr");
var symbolCell = document.createElement("td");
var priceCell = document.createElement("td");
symbolCell.textContent = stock.symbol;
priceCell.textContent = stock.price;
row.appendChild(symbolCell);
row.appendChild(priceCell);
table.appendChild(row);
}
document.getElementById("stocks-list").appendChild(table);
});
connection.on("updateStockPrice", function (stock) {
// Update the stock price.
document.getElementById("stock-price").textContent =
stock.symbol + ": " + stock.price;
});
connection.start().then(function () {
connection.invoke("GetAllStocks").catch(function (err) {
return console.error(err.toString());
});
});
setInterval(function () {
var symbols = ['MSFT', 'AAPL', 'GOOG', 'AMZN', 'FB'];
var symbol = symbols[Math.floor(Math.random() * symbols.length)];
connection.invoke("GetStock", symbol).catch(function (err) {
return console.error(err.toString());
});
}, 1000);
</script>
}
在此示例中,我们使用StockTicker类和StockTickerHub类创建了一个简单的股票行情跟踪器。其中StockTicker是一个单例,用于在一定时间间隔内更新所有股票价格的模拟数据,并将更新后的股票价格发送给所有连接的客户端。StockTickerHub则包含两个方法,分别用于获取所有股票价格和特定股票的价格,并使用Clients对象将数据发送到客户端。
在客户端上,我们使用connection.on()方法订阅“updateAllStocks”和“updateStockPrice”事件。当连接成功时,我们通过connection.invoke()方法调用服务器上的GetAllStocks方法,以获取所有股票价格。我们还使用javascript中的setInterval()函数,每秒调用服务器上的GetStock方法,随机地请求一个股票的价格,并实时更新股票价格。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SignalR Self Host+MVC等多端消息推送服务(一) - Python技术站