.NET Core學習筆記(5)——WebAPI從Server端push消息到Client

標題起得有點厲害,漢字夾雜着E文,不符合教育部公佈的「向社會推薦使用的外語詞中文譯名」規範。不過他管不着我。寫本篇的原由,是重構一個現有的WinForms程序,將Server端的部分邏輯從raw socket通信的方式,改成調用WebAPI。重構則是由於原先代碼有嚴重的性能問題,而組裏並無可以寫好socket通信的同窗。javascript

WebAPI的編寫相對就簡單多了,但原先從Server端push消息到Client的功能就須要找到替代的解決方案。因此有了本篇對於SignalR的介紹。html

「ASP.NET Core SignalR 是一個開源代碼庫,它簡化了嚮應用添加實時 Web 功能的過程。 實時 Web 功能使服務器端代碼可以即時將內容推送到客戶端。」看不懂不能怪我,MSDN上的原話。簡單能夠理解爲SignalR是一個基於WebSocket的庫,可以幫助咱們避免直接使用socket,而寫出一些性能誇張的代碼……java

SignalR的基本push流程是這樣的,首先Server端有一個Hub類,Hub類中會定義一個方法,該方法會在某個時機被觸發,而在該方法內部,會有一個Clients.All.SendAsync之類的操做。而後經過該SendAsync方法,來將消息內容傳遞給事先定義好的Client端的方法。git

    public class TestCaseHub : Hub
    {
        public async Task SayHello()
        {
            await Clients.All.SendAsync("AreYouOK");
        }
    }

上述代碼中(TestSignalRServer工程的Hubs\TestCaseHub.cs),TestCaseHub中的SayHello方法執行時,會調用client端的AreYouOK方法。爲了簡單起見,這個方法沒有參數。github

SignalR客戶端的結構也很簡單,打開TestSignalRClient工程的program.cs文件,僅有的Main方法以下:api

        static void Main(string[] args)
        {
            HubConnection connection = new HubConnectionBuilder().WithUrl("https://localhost:44306/TestCaseHub").Build();
            
 connection.On("AreYouOK", () =>
            {
                Console.WriteLine("Fine, thank you. And you?");
            });
  
            connection.StartAsync();
            Console.WriteLine("Start connect");
            Console.ReadKey();
        }

首先經過Hub的url build出HubConnection對象。再經過HubConnection的On方法,向Server端註冊AreYouOK方法。這個方法會在Server端經過SendAsync來被調用。服務器

可能有新同窗會問Hub的url是什麼,這是由於SignalR是基於ASP.Net Core工程的,因此TestSignalRServer工程實際是一個Visual Studio裏建立的Web Application,咱們打開Startup類,能夠看到註冊了SignalR的service和TestCaseHub類的route映射。(TestSignalRServer的代碼是.NET Core 2.2的,後面咱們還會建立.NET Core 3.1的,經過WebApi調用觸發的SignalR通知,代碼會有細微的差異)app

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSignalR();
        }
  
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
  
            app.UseFileServer();
            app.UseSignalR(routes =>
            {
                routes.MapHub<TestCaseHub>("/testcasehub");
            });
        }

在TestSignalRServer這個Web Application中,最終是經過html頁面上的button,執行javascript來觸發SayHello方法,最終將通知發送到Console Client。而咱們實際的需求,是須要一個WebApi來觸發SignalR通知。還記得開頭提到的WinForms程序嗎?由WinForms程序調用WebApi,傳遞要push給Console Client的參數,再經過包含SignalR Hub的WebApi完成push。框架

首先咱們建立一個空的ASP.NET Core Web Application。模板類型選擇API。socket

默認的API模板會包含一個WeatherForecastController,此時按下F5運行,能夠測試下環境是否配置正確。

接下來咱們建立NotificationHub。啥也不用寫,空的就好了。

    public class NotificationHub: Hub
    {
    }

而後照着WeatherForecastController抄襲一個NotificationController。NotificatoinHub空着的緣由在於咱們將SendAsync寫在這裏了。具體能夠參考「Send messages from outside a hub」。ASP.NET Core能夠經過自帶的依賴注入框架,在Controller裏獲取IHubContext對象。

    [Route("api/[controller]")]
    [ApiController]
    public class NotificationController : ControllerBase
    {
        private readonly IHubContext<NotificationHub> _hubContext;
  
        public NotificationController(IHubContext<NotificationHub> hubContext)
        {
            _hubContext = hubContext;
        }
  
        [HttpGet]
        public async Task<IActionResult> Notify()
        {
            await _hubContext.Clients.All.SendAsync("Notify", $"It's time: {DateTime.Now}");
            return Ok();
        }
    }

在Startup裏添加上對SignalR的service使用和endpoint設置,Server端的編寫就結束了。

      public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddSignalR();
        }
  
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
  
            app.UseHttpsRedirection();
  
            app.UseRouting();
  
            app.UseAuthorization();
  
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
                endpoints.MapHub<NotificationHub>("/notificationHub");
            });
        }

Client的代碼和以前.NET Core 2.2的例子基本沒有區別,惟一不一樣此次帶了一個string參數。強類型的參數SignalR也是支持的,會自動完成序列化和反序列化的操做。

            var connection = new HubConnectionBuilder()
                .WithUrl("https://localhost:44354/NotificationHub")
                .Build();
  
            await connection.StartAsync();
  
            connection.On<string>("Notify", (a) =>
            {
                Console.WriteLine($"Notify: {a}");
            });

若是發現找不到HubConnectionBuilder,記得去NuGet安裝Microsoft.AspNetCore.SignalR.Client。

將包含NotificationConroller的Web Applicatin和Console Client分別啓動後。咱們只須要訪問https://localhost:xxxx/api/notification這個地址,便可觸發SignalR通知。從下圖看這是一個簡單的報時通知。

本篇介紹瞭如何建立ASP.NET Core的WebApi,實現從Server端push消息到Client。同時將觸發通知的操做放到WebApi的Controller裏,從而避免了html和javascript的編寫,緩解了傳統桌面開發人員的不適,延長了部分壽命。

Sample工程:

SignalRTest基於.NET Core 2.2,在抄襲了官方sample的基礎上,實現點擊html頁面的button推送小文件給Client的功能。

https://github.com/manupstairs/SignalRTest

SignalRTest1一看名字就很隨性,基於.NET Core 3.1,寫成WebApi的形式,做爲專門的Notification Service。

https://github.com/manupstairs/SignalRTest1

相關文章
相關標籤/搜索