求带可用WebSocket传输的ASP.NET Core 6+SignalR+Angular项目模板
ASP.NET Core 6 + Angular集成SignalR WebSocket的方案
现成项目模板说明
官方dotnet new angular模板并未预集成SignalR WebSocket,你可以通过两种方式获取可用模板:
- 社区自定义模板:部分开发者会分享预配置好的模板,但版本可能存在滞后性,更可靠的方式是手动配置(下文重点说明)。
- 自制模板:按照下文步骤配置好项目后,可通过
dotnet new template命令将其打包为自定义模板,后续可直接调用使用。
手动配置步骤(解决WebSocket无法运行问题)
后端(ASP.NET Core 6)配置
- 安装SignalR包
在项目根目录执行命令:
dotnet add package Microsoft.AspNetCore.SignalR
- 配置Program.cs
需确保CORS、SignalR服务和中间件的顺序正确:
var builder = WebApplication.CreateBuilder(args); // 添加SignalR服务 builder.Services.AddSignalR(); // 配置CORS,允许Angular客户端的WebSocket请求 builder.Services.AddCors(options => { options.AddPolicy("AllowAngularClient", policy => { policy.WithOrigins("http://localhost:4200") // 替换为你的Angular运行地址 .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); // 必须开启,WebSocket请求需携带凭证 }); }); builder.Services.AddControllersWithViews(); var app = builder.Build(); if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); // 启用CORS,需放在UseRouting之后、UseAuthorization之前 app.UseCors("AllowAngularClient"); app.UseAuthorization(); // 映射默认路由 app.MapControllerRoute( name: "default", pattern: "{controller}/{action=Index}/{id?}"); // 映射SignalR Hub app.MapHub<ChatHub>("/chatHub"); app.Run();
- 创建SignalR Hub类
在项目中新建Hubs/ChatHub.cs:
using Microsoft.AspNetCore.SignalR; namespace YourProjectNamespace.Hubs; public class ChatHub : Hub { // 示例:发送消息方法 public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } }
前端(Angular)配置
- 安装SignalR客户端包
在ClientApp目录执行命令:
npm install @microsoft/signalr
- 创建SignalR服务
新建src/app/signalr.service.ts:
import { Injectable } from '@angular/core'; import { HubConnection, HubConnectionBuilder } from '@microsoft/signalr'; @Injectable({ providedIn: 'root' }) export class SignalrService { private hubConnection!: HubConnection; startConnection(): void { this.hubConnection = new HubConnectionBuilder() .withUrl('https://localhost:5001/chatHub', { skipNegotiation: true, // 跳过传输协商,直接使用WebSocket transport: 0 // 0对应WebSocket传输,等价于HttpTransportType.WebSockets }) .build(); this.hubConnection.start() .then(() => console.log('WebSocket连接成功')) .catch(err => console.error('连接失败:', err)); } // 注册消息接收监听 onReceiveMessage(callback: (user: string, message: string) => void): void { this.hubConnection.on('ReceiveMessage', callback); } // 发送消息到服务端 sendMessage(user: string, message: string): void { this.hubConnection.invoke('SendMessage', user, message) .catch(err => console.error('发送消息失败:', err)); } }
注意:withUrl中的地址需与后端MapHub的地址完全匹配,包括协议(http/https)和端口。
- 在组件中使用SignalR服务
修改src/app/app.component.ts:
import { Component, OnInit } from '@angular/core'; import { SignalrService } from './signalr.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { user = '测试用户'; message = ''; messages: {user: string, text: string}[] = []; constructor(private signalrService: SignalrService) {} ngOnInit(): void { this.signalrService.startConnection(); this.signalrService.onReceiveMessage((user, message) => { this.messages.push({user, text: message}); }); } sendMessage(): void { if (this.message.trim()) { this.signalrService.sendMessage(this.user, this.message); this.message = ''; } } }
- 更新组件模板
修改src/app/app.component.html:
<div class="message-input"> <input [(ngModel)]="user" placeholder="输入用户名" /> <input [(ngModel)]="message" placeholder="输入消息" /> <button (click)="sendMessage()">发送</button> </div> <div class="message-list"> <div *ngFor="let msg of messages"> <strong>{{msg.user}}:</strong> {{msg.text}} </div> </div>
记得在AppModule中导入FormsModule,以支持ngModel指令。
常见问题排查
- CORS错误:确保CORS策略中
AllowCredentials已开启,且源地址与Angular运行地址一致,不能使用*作为源(会与AllowCredentials冲突)。 - 混合内容问题:如果后端使用HTTPS,前端也必须使用HTTPS,开发环境可执行
dotnet dev-certs https --trust信任开发证书。 - 传输回退:默认SignalR会协商传输方式,若WebSocket不可用会回退到ServerSentEvents,通过
skipNegotiation: true和指定WebSocket传输可强制使用WebSocket。
内容的提问来源于stack exchange,提问作者Marc Johnston
相关产品推荐
相关产品推荐

