Nguon: Microsoft Learn · .NET 8.0
Hướng dẫn: ASP.NET Core SignalR với TypeScript và Webpack
Hướng dẫn này trình bày cách xây dựng ứng dụng web ASP.NET Core SignalR sử dụng TypeScript và Webpack (công cụ đóng gói) để bundle (đóng gói) các tài nguyên phía client.
Tổng quan
Hướng dẫn này bao gồm:
- Tạo ứng dụng ASP.NET Core SignalR
- Cấu hình server SignalR
- Thiết lập build pipeline (đường dẫn build) sử dụng Webpack
- Cấu hình SignalR TypeScript client
- Kích hoạt giao tiếp client-server
Điều kiện tiên quyết
Yêu cầu chung
Cho Visual Studio
- Phiên bản mới nhất của Visual Studio với workload ASP.NET and web development
- .NET 8.0 SDK (hoặc phiên bản phù hợp)
Cho Visual Studio Code
- Visual Studio Code
- C# Dev Kit for Visual Studio Code
- .NET 8.0 SDK
Thiết lập dự án
Tạo ASP.NET Core Web App
Visual Studio:
- File > New > Project/Solution
- Chọn template ASP.NET Core Empty
- Đặt tên dự án là
SignalRWebpack - Chọn .NET 8.0 (Long Term Support)
Visual Studio Code:
dotnetcli
dotnet new web -o SignalRWebpack code -r SignalRWebpack
Cài đặt hỗ trợ TypeScript
Thêm NuGet package Microsoft.TypeScript.MSBuild:
dotnetcli
dotnet add package Microsoft.TypeScript.MSBuild
Cấu hình Server
1. Cấu hình Program.cs
Thêm SignalR services:
csharp
var builder = WebApplication.CreateBuilder(args); builder.Services.AddSignalR();
Thêm static file serving (phục vụ file tĩnh):
csharp
var app = builder.Build(); app.UseDefaultFiles(); app.UseStaticFiles();
2. Tạo ChatHub
Tạo file Hubs/ChatHub.cs:
csharp
using Microsoft.AspNetCore.SignalR;
namespace SignalRWebpack.Hubs;
public class ChatHub : Hub
{
public async Task NewMessage(long username, string message) =>
await Clients.All.SendAsync("messageReceived", username, message);
}3. Map Hub Route
Trong Program.cs:
csharp
using SignalRWebpack.Hubs;
// ... các cấu hình khác ...
app.MapHub<ChatHub>("/hub");Cấu hình Client
1. Khởi tạo npm
console
npm init -y
2. Cập nhật package.json
json
{
"name": "signalrwebpack",
"version": "1.0.0",
"private": true,
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --mode=development --watch",
"release": "webpack --mode=production",
"publish": "npm run release && dotnet publish -c Release"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"devDependencies": {
"clean-webpack-plugin": "4.0.0",
"css-loader": "7.1.3",
"html-webpack-plugin": "5.6.6",
"mini-css-extract-plugin": "2.10.0",
"ts-loader": "9.5.4",
"typescript": "5.9.3",
"webpack": "5.104.1",
"webpack-cli": "6.0.1"
},
"dependencies": {
"@microsoft/signalr": "^8.0.0",
"@types/node": "^20.0.0"
}
}3. Cài đặt các npm Package
console
npm i -D -E clean-webpack-plugin css-loader html-webpack-plugin mini-css-extract-plugin ts-loader typescript webpack webpack-cli npm i @microsoft/signalr @types/node
4. Tạo webpack.config.js
javascript
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/index.ts",
output: {
path: path.resolve(__dirname, "wwwroot"),
filename: "[name].[chunkhash].js",
publicPath: "/",
},
resolve: {
extensions: [".js", ".ts"],
},
module: {
rules: [
{
test: /\.ts$/,
use: "ts-loader",
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new MiniCssExtractPlugin({
filename: "css/[name].[chunkhash].css",
}),
],
};5. Tạo các Source File
src/index.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>ASP.NET Core SignalR with TypeScript and Webpack</title>
</head>
<body>
<div id="divMessages" class="messages"></div>
<div class="input-zone">
<label id="lblMessage" for="tbMessage">Message:</label>
<input id="tbMessage" class="input-zone-input" type="text" />
<button id="btnSend">Send</button>
</div>
</body>
</html>src/css/main.css
css
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
}
.input-zone {
align-items: center;
display: flex;
flex-direction: row;
margin: 10px;
}
.input-zone-input {
flex: 1;
margin-right: 10px;
}
.message-author {
font-weight: bold;
}
.messages {
border: 1px solid #000;
margin: 10px;
max-height: 300px;
min-height: 300px;
overflow-y: auto;
padding: 5px;
}src/tsconfig.json
json
{
"compilerOptions": {
"target": "es5"
}
}src/index.ts
typescript
import * as signalR from "@microsoft/signalr";
import "./css/main.css";
const divMessages: HTMLDivElement = document.querySelector("#divMessages");
const tbMessage: HTMLInputElement = document.querySelector("#tbMessage");
const btnSend: HTMLButtonElement = document.querySelector("#btnSend");
const username = new Date().getTime();
const connection = new signalR.HubConnectionBuilder()
.withUrl("/hub")
.build();
connection.on("messageReceived", (username: string, message: string) => {
const m = document.createElement("div");
const author = document.createElement("div");
author.className = "message-author";
author.textContent = username;
const content = document.createElement("div");
content.textContent = message;
m.append(author, content);
divMessages.appendChild(m);
divMessages.scrollTop = divMessages.scrollHeight;
});
connection.start().catch((err) => document.write(err));
tbMessage.addEventListener("keyup", (e: KeyboardEvent) => {
if (e.key === "Enter") {
send();
}
});
btnSend.addEventListener("click", send);
function send() {
connection.send("newMessage", username, tbMessage.value)
.then(() => (tbMessage.value = ""));
}Kiểm tra ứng dụng
Build với Webpack
console
npm run release
Lệnh này:
- Dọn dẹp thư mục
wwwroot - Transpile (chuyển đổi) TypeScript sang JavaScript
- Minify (nén) JavaScript đã tạo
- Sao chép các file đã xử lý vào
wwwroot - Chèn các thẻ
<link>và<script>vàowwwroot/index.html
Chạy ứng dụng
Visual Studio:
- Chọn Debug > Start without debugging
- Ứng dụng phục vụ tại
https://localhost:<port>
Visual Studio Code:
dotnetcli
dotnet run
Kiểm tra chức năng
- Mở ứng dụng trong một cửa sổ trình duyệt
- Mở một instance trình duyệt khác và điều hướng đến cùng URL
- Nhập tin nhắn vào hộp text và nhấn Enter hoặc click Send
- Xác minh tin nhắn xuất hiện ở cả hai cửa sổ trình duyệt với username (tên người dùng) duy nhất
Các khái niệm chính
Webpack Scripts
- build: Chế độ development (phát triển) với file watching (theo dõi file) - chỉ transpile, không minify
- release: Chế độ production (sản xuất) với các tối ưu hóa (minification, tree shaking)
- publish: Release build + .NET CLI publish
Giao tiếp SignalR
- Client gửi: Gọi method
newMessagevới username và message - Server nhận: Method hub
NewMessage - Server broadcast:
SendAsync("messageReceived", ...)đến tất cả các client đã kết nối - Client nhận: Event handler (trình xử lý sự kiện) lắng nghe các message
messageReceived
Tính năng TypeScript Client
HubConnectionBuilder: Tạo và cấu hình kết nối serverwithUrl(): Chỉ định endpoint (điểm cuối) của hubconnection.on(): Đăng ký message handlerconnection.send(): Gửi tin nhắn đến server