- vừa được xem lúc

Hiển thị giá cổ phiếu VinFast real time với web apps Blazor và Azure SignalR Service serverless mode

0 0 26

Người đăng: SPIDER MAN

Theo Viblo Asia

Mở đầu

Đây sẽ là một series bài viết bao gồm:

  • Phần 1: Tạo một web apps bằng Blazor hiển thị giá cổ phiếu VinFast real time.
  • Phần 2: Truyền phát dữ liệu real time cho một nhóm clients chỉ định.
  • Phần 3: Bảo mật kết hợp xác thực với function keyazure authentication bằng access token sau khi deploy lên azure.

Thật sự thì mình cũng không có nhiều thời gian. Nhưng trong quá trình phát triển một dự án, teams của mình đã gặp khá nhiều khó khăn do tài liệu của microsoft về Azure SignalR Service đặc biệt là với serverless mode quá nghèo nàn. Nên mình quyết định sẽ viết series này và mình hi vọng là nó có ích.

Nhưng tại sao lại là serverless mode? Với Serverless mode của Azure SignalR Service, cũng giống như với Azure Functions chúng ta không cần phải quản lý các máy chủ để triển khai dịch vụ SignalR. Chúng ta chỉ cần tập trung vào việc phát triển ứng dụng của mình, mà không cần phải lo lắng về việc quản lý cơ sở hạ tầng máy chủ. Azure SignalR Service sẽ tự động mở rộng và quản lý cơ sở hạ tầng, đơn giản hóa việc triển khai và mở rộng dịch vụ SignalR.

Demo

Về công nghệ sẽ sử dụng

  • Azure SignalR Service (serverless mode)
  • Azure Functions (c#)
  • Blazor WebAssembly

Tạo Azure SignalR Service

Truy cập https://portal.azure.com và nhấn vào Create a Resource.

Tạo SignalR, nhớ chọn Serverless ở mục Service mode:

Sau cùng, chọn Review + create. Sau khi hoàn tất, hãy chuyển đến dịch vụ. Copy Connection string và ghi chú nó cho phần tiếp theo.

Tạo Azure Functions với Visual Studio

image.png

Chọn Functions worker .NET 6 image.png

Mở file local.settings.json và thay thế như sau, cũng như đảm bảo rằng Connection string vừa lấy ở trên cũng được thêm vào.

{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "", "FUNCTIONS_WORKER_RUNTIME": "dotnet", "AzureSignalRConnectionString": "<YOUR CONNECTION STRING>" }, "Host": { "LocalHttpPort": 7071, "CORS": "*", "CORSCredentials": false }
}

Chúng ta sẽ cần thêm NuGet Package Microsoft.Azure.WebJobs.Extensions.SignalRService vào project.

dotnet add package Microsoft.Azure.WebJobs.Extensions.SignalRService --version 1.1.0

Tiếp theo, tạo Functions.cs ở thư mục gốc của Azure Functions. Ở đây chúng ta dùng AuthorizationLevel.Function, khi chạy ở môi trường local thì sẽ vẫn vượt được xác thực thoải mái. Nhưng khi deploy lên Azure thì ở phía client chúng ta sẽ phải config thêm. Cũng như, chúng ta sẽ thêm xác thực "Authentication" cho Azure Functions ở phần 3 của series bài viết nhé.

using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;
using Newtonsoft.Json.Linq;
using System;
using System.Net.Http;
using System.Threading.Tasks; namespace StockPriceDemo;
public static class Functions
{ // This will manage connections to SignalR [FunctionName("negotiate")] public static SignalRConnectionInfo GetSignalRInfo( [HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req, [SignalRConnectionInfo(HubName = "stockHub")] SignalRConnectionInfo connectionInfo) { return connectionInfo; } /// <summary> /// Get stock prices of VinFast every 10 seconds /// </summary> /// <param name="myTimer"></param> /// <param name="signalRMessage"></param> [FunctionName("auto_getstockprice_vfs_periodically")] public static async Task GetStockPriceOfVFSPeriodically( [TimerTrigger("*/10 * * * * *")] TimerInfo myTimer, [SignalR(HubName = "stockHub")] IAsyncCollector<SignalRMessage> signalRMessage) { string apiKey = "7KJVS7FK2BTK1A1W"; string symbol = "VFS"; StockPrice stockPrice = null; using HttpClient client = new HttpClient(); string url = $"https://www.alphavantage.co/query?function=GLOBAL_QUOTE" + $"&symbol={symbol}" + $"&apikey={apiKey}"; try { HttpResponseMessage response = await client.GetAsync(url); if (response.IsSuccessStatusCode) { string jsonString = await response.Content.ReadAsStringAsync(); JObject stockInfoRes = JObject.Parse(jsonString); if (stockInfoRes["Global Quote"] is null) throw new Exception(); stockPrice = new StockPrice { Name = "VFS", Price = stockInfoRes["Global Quote"]["05. price"].ToString() }; } } catch (Exception) { stockPrice = new StockPrice { Name = "VFS", Price = "Err" }; } await signalRMessage.AddAsync( new SignalRMessage { Target = "stockPrice", Arguments = new[] { stockPrice } }); } /// <summary> /// Send stock prices of VinFast to all clients in hub /// </summary> /// <param name="myTimer"></param> /// <param name="signalRMessage"></param> [FunctionName("post-stockprice_vfs")] public static async Task PostStockPriceOfTM( [HttpTrigger(AuthorizationLevel.Function, "post")] StockPrice stockPriceVFS, [SignalR(HubName = "stockHub")] IAsyncCollector<SignalRMessage> signalRMessage, HttpRequest req) { // Send the stock price to the SignalR Hub and it will be distributed to connected clients via SignalR await signalRMessage.AddAsync( new SignalRMessage { Target = "stockPrice", Arguments = new[] { stockPriceVFS } }); } } public class StockPrice
{ public string Name { get; set; } public string Price { get; set; }
}

Tạo client với Blazor WASM

Nhấn chuột phải vào Solution -> Add -> New Project...

image.png

Thêm NuGet Package Microsoft.AspNetCore.SignalR.Client vào project.

dotnet add package Microsoft.AspNetCore.SignalR.Client --version 3.1.4

Mở Index.razor trong folder Pages và thay thế toàn bộ bằng đoạn code bên dưới.

@page "/" @using Microsoft.AspNetCore.SignalR.Client <h1>Connection: @hubConnection.State</h1>
<hr>
<h3>Gia co phieu VinFast: @stockPrice.Price <span style="color:seagreen">(Update-count: @countNumber)</span></h3> @code { private HubConnection hubConnection; // For connecting to SignalR private StockPrice stockPrice = new StockPrice(); // Stock price to display private int countNumber = 0; private readonly string functionAppBaseUri = "http://localhost:7071/api"; // URL for function app protected override async Task OnInitializedAsync() { // Create a hub connection to the function app as we'll go via the function for everything SignalR hubConnection = new HubConnectionBuilder() .WithUrl(functionAppBaseUri) .Build(); // Registers handler that will be invoked when the hub method with the specified method name is invoked hubConnection.On<StockPrice>("stockPrice", (stockPriceRes) => { stockPrice = stockPriceRes; countNumber++; StateHasChanged(); }); await hubConnection.StartAsync(); // Start connection } // Check we're connected public bool IsConnected => hubConnection.State == HubConnectionState.Connected; public class StockPrice { public string Name { get; set; } public string Price { get; set; } }
}

Nhấn chuột phải vào Solution -> properties -> Common Properties -> Multiple startup projects để chạy cùng lúc cả hai Azure Functions và Blazor Client. Thành quả sẽ như ở demo phía trên.

Kết luận

Bài cũng đã khá dài nên mình sẽ không giải thích cụ thể ý nghĩa của từng dòng code, nhưng nếu có vấn đề gì không hiểu hoặc sai sót của mình thì các bạn cứ comment phía dưới nhé. Mình rất sẵn lòng. Happy coding!

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Lambda AWS

Giới thiệu. Nếu bạn là 1 developer, đúng rồi đó, người mà luôn được mọi người nhờ sửa tủ lạnh, ti vi, quạt máy, ống nước, đủ thứ loại trên đời, khi bạn xây dựng một ứng dụng, bạn sẽ muốn được nhiều người sử dụng, trải nghiệm và đánh giá tốt.

0 0 35

- vừa được xem lúc

Ứng dụng Serverless thực tế trên AWS (Part 1)

Lời nói đầu. Ở đâu đó có thể các bạn đã nghe thấy khái niệm serverless hay chạy ứng dụng không mà không cần sử dụng một server nào.

0 0 84

- vừa được xem lúc

Chính xác thì "Serverless" là gì?

Giới thiệu về Serverless Architecture. Chính xác thì "serverless" là gì.

0 0 49

- vừa được xem lúc

Serverless Series (Golang) - Bài 1 - Serverless và AWS Lambda

Giới thiệu. Chào các bạn tới với series về Serverless.

0 0 69

- vừa được xem lúc

Serverless Series (Golang) - Bài 2 - Build REST API with AWS API Gateway

Giới thiệu. Chào các bạn tới với series về Serverless, ở bài trước chúng ta đã nói về kiến trúc Serverless là gì, AWS Lambda là gì và nó đóng vai trò như thế nào trong mô hình Serverless.

0 0 39

- vừa được xem lúc

Serverless Series (Golang) - Bài 3 - AWS Lambda + DynamoDB for data persistence

Giới thiệu. Chào các bạn tới với series về Serverless, ở bài trước chúng ta đã nói về cách sử dụng AWS API Gateway kết hợp với AWS Lambda để xây dựng REST API theo mô hình Serverless.

0 0 27