Nguon: Microsoft Learn · .NET 8.0

Hướng dẫn: Bắt đầu với ASP.NET Core SignalR sử dụng TypeScript và Webpack

Nguồn: Tutorial: Get started with ASP.NET Core SignalR using TypeScript and Webpack

Hướng dẫn này mô tả cách xây dựng ứng dụng web ASP.NET Core SignalR sử dụng TypeScript (ngôn ngữ lập trình có kiểu tĩnh mở rộng JavaScript) và Webpack (công cụ đóng gói module) để đóng gói và biên dịch tài nguyên phía client.

Tổng quan

Hướng dẫn này minh họa cách:

Điều kiện tiên quyết

Các bước cấu hình chính

1. Tạo ứng dụng web ASP.NET Core

Tạo một dự án ASP.NET Core rỗng và thêm gói NuGet Microsoft.TypeScript.MSBuild để bật tính năng biên dịch TypeScript.

2. Cấu hình Server

Trong file Program.cs:

csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSignalR();

var app = builder.Build();

app.UseDefaultFiles();
app.UseStaticFiles();

app.MapHub<ChatHub>("/hub");

3. Tạo SignalR Hub (trung tâm SignalR)

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);
}

4. Cấu hình pipeline biên dịch phía client

Tạo file package.json với các npm scripts (lệnh chạy npm):

json
{
  "name": "signalrwebpack",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "webpack --mode=development --watch",
    "release": "webpack --mode=production",
    "publish": "npm run release && dotnet publish -c Release"
  },
  "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": "^10.0.0",
    "@types/node": "^25.0.10"
  }
}

5. Cấu hình Webpack

Tạo file 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",
        }),
    ],
};

6. Các file nguồn phía client

Tạo thư mục src với các file sau:

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");

  m.innerHTML = `<div class="message-author">${username}</div><div>${message}</div>`;

  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

  1. Chạy npm run release để biên dịch các tài nguyên phía client ở chế độ production
  2. Chạy ứng dụng bằng dotnet run hoặc thông qua Visual Studio
  3. Mở ứng dụng trong trình duyệt tại https://localhost:<port>
  4. Mở thêm một tab/trình duyệt khác và kiểm tra việc gửi tin nhắn thời gian thực giữa các client

Hướng dẫn bao gồm các chỉ dẫn chi tiết cho cả Visual Studio và Visual Studio Code.