SignalR Self Host+MVC等多端消息推送服务(一)

“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技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • IntelliJ IDEA 2019如何匹配大小写开关?IntelliJ IDE匹配大小写开关教程

    IntelliJ IDEA 2019如何匹配大小写开关? 在IntelliJ IDEA 2019中,你可以通过以下步骤来开启或关闭匹配大小写功能: 打开IntelliJ IDEA 2019。 在菜单栏中选择 \”File\”(文件)。 从下拉菜单中选择 \”Settings\”(设置)。 在弹出的窗口中,选择 \”Editor\”(编辑器)。 在左侧的面板中…

    other 2023年8月16日
    00
  • Nginx教程(四) Location配置与ReWrite语法

    下面是“Nginx教程(四)Location配置与ReWrite语法的完整攻略”的详细讲解,包括Location配置、ReWrite语法、注意事项和两个示例等方面。 Location配置 在Nginx中,Location配置用于匹配请求的URL,并指定相应的处理方式。Location配置可以使用正则表达式进行匹配,支持多种匹配方式,包括前缀匹配、精确匹配、正…

    other 2023年5月5日
    00
  • C/C++ 中堆和栈及静态数据区详解

    C/C++ 中堆和栈及静态数据区详解 在C/C++中,堆、栈和静态数据区是三个重要的内存分配区域。它们在内存中的位置和分配方式不同,对于程序的内存管理和数据存储有着不同的影响。 堆(Heap) 堆是一块动态分配的内存区域,用于存储程序运行时动态分配的数据。堆的分配和释放是由程序员手动控制的,通过使用malloc、calloc、realloc等函数进行分配,使…

    other 2023年8月1日
    00
  • 查看Linux系统是32位还是64位的方法总结

    查看Linux系统是32位还是64位的方法总结 要确定Linux系统是32位还是64位,可以使用以下方法: 方法一:使用命令行查看 打开终端或命令行界面。 输入以下命令并按下回车键: uname -m 系统将返回一个字符串,表示系统的架构。如果返回的是x86_64,则表示系统是64位的;如果返回的是i686或i386,则表示系统是32位的。 示例说明: 输入…

    other 2023年7月28日
    00
  • 详解Java中方法重写与重载的区别(面试高频问点)

    下面详细讲解Java中方法重写与重载的区别。 方法重载 方法重载指的是在类中定义两个或以上的方法,它们有相同的名字但参数列表不同。Java会根据传入方法的参数的类型和数量的不同,自动匹配出正确的方法来执行。 具体来说,方法的重载需要满足以下条件: 方法的名称必须相同 方法的参数列表必须不同 方法的返回类型可以相同也可以不同 下面是一个方法重载的示例: pub…

    other 2023年6月26日
    00
  • 使用idea当中的快捷键快速查看继承关系或其图表的两种方法

    以下是详细讲解“使用Idea中的快捷键快速查看继承关系或其图表的两种方法的完整攻略”,过程中至少包含两条示例说明的标准Markdown格式文本: 使用Idea中的快捷键快速查看继承关系或其图表的两种方法 Idea是一款流行的Java开发工具,提供了许多快捷键和功能,可以帮助开发人员提高效率。本文将介绍如何使用Idea中的快捷键快速查看Java类的继承关系或其…

    other 2023年5月10日
    00
  • C语言实现enum枚举

    当使用C语言编程时,可以使用enum关键字来定义枚举类型。枚举类型允许我们定义一组具有离散值的常量。下面是实现enum枚举的完整攻略: 首先,使用enum关键字定义一个枚举类型。枚举类型的名称应该是唯一的,并且按照C语言的命名规范进行命名。例如,我们可以定义一个表示颜色的枚举类型: enum Color { RED, GREEN, BLUE }; 在上面的示…

    other 2023年8月15日
    00
  • 子网掩码和IP地址的关系

    子网掩码和IP地址的关系 子网掩码(Subnet Mask)是用于划分网络中主机和网络地址的一种技术。它与IP地址(Internet Protocol Address)密切相关,用于确定一个IP地址的网络部分和主机部分。在本攻略中,我们将详细讲解子网掩码和IP地址之间的关系,并提供两个示例来说明。 1. IP地址的结构 IP地址是一个32位的二进制数,通常以…

    other 2023年7月30日
    00
合作推广
合作推广
分享本页
返回顶部