Angular中调用SignalR的invoke方法传文件时服务端接口未触发如何解决
问题根因
SignalR 默认使用 JSON 序列化器传输数据,不支持直接序列化 FormData 对象,也无法在服务端自动绑定到 IFormFile 类型,这是你调用服务端方法无响应的核心原因。IFormFile 是 ASP.NET Core 用于绑定 HTTP 表单请求的类型,不适用于 SignalR 的调用场景。
解决方案
第一步:修改前端传参逻辑
不要用 FormData 封装参数,将文件转为 Base64 字符串后,和其他参数一起传递:
async fileUpload(username: string, file: File) { // 把File对象转成Base64字符串 const fileBase64 = await this.convertFileToBase64(file); return this.hubConnection.invoke('FileUpload', { recipientUsername: username, fileName: file.name, contentType: file.type, fileBase64: fileBase64 }).catch(error => console.log(error)); } // 辅助方法:File转Base64 private convertFileToBase64(file: File): Promise<string> { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => { // 去掉base64的头部标识 比如data:image/png;base64, const base64 = (reader.result as string).split(',')[1]; resolve(base64); }; reader.onerror = error => reject(error); }); }
第二步:修改服务端 FileDto 定义
替换 IFormFile 为对应的参数字段:
public class FileDto { public string RecipientUsername { get; set; } public string FileName { get; set; } public string ContentType { get; set; } public string FileBase64 { get; set; } }
第三步:修改服务端文件存储逻辑
把 Base64 字符串转为字节数组后写入文件:
public async Task FileUpload(FileDto createFileDto) { var username = Context.User.GetUsername(); if(username == createFileDto.RecipientUsername.ToLower()) throw new HubException("You cannot send file to youself"); var sender = await _userRepository.GetUserByUsernameAsync(username); var recipient = await _userRepository.GetUserByUsernameAsync(createFileDto.RecipientUsername); if(recipient == null) throw new HubException("Not Found User"); var message = new Message(); string groupName =""; if(!string.IsNullOrEmpty(createFileDto.FileBase64)) { if(!Directory.Exists(AppDirectory)) Directory.CreateDirectory(AppDirectory); var fileBytes = Convert.FromBase64String(createFileDto.FileBase64); var fileFormat = Path.GetExtension(createFileDto.FileName); var fileName = DateTime.Now.Ticks.ToString() + fileFormat; var path = Path.Combine(AppDirectory, fileName); await File.WriteAllBytesAsync(path, fileBytes); message = new Message { Sender = sender, Recipient = recipient, SenderUsername = sender.UserName, RecipientUsername = recipient.UserName, IsFile = true, Content = "", FileName = createFileDto.FileName, FileFormat = fileFormat, ContentType = createFileDto.ContentType, FilePath = path }; groupName = GetGroupName(sender.UserName, recipient.UserName); var group = await _messageRepository.GetMessageGroup(groupName); if (group.Connections.Any(x => x.Username == recipient.UserName)) { message.DateRead = DateTime.UtcNow; } else { var connections = await _tracker.GetConnectionsForUser(recipient.UserName); if (connections != null) { await _presenceHub.Clients.Clients(connections).SendAsync("NewMessageReceived", new { username = sender.UserName, knownAs = sender.KnownAs }); } } _messageRepository.AddMessage(message); } if(await _messageRepository.SaveAllAsync() && groupName != "") { await Clients.Group(groupName).SendAsync("NewMessage",_mapper.Map<MessageDto>(message)); } }
可选检查项
如果修改后还是无法触发方法,检查以下配置:
- 确认前端 SignalR 连接已经成功建立,没有权限验证失败等报错
- 如果服务端配置了
JsonSerializerOptions.PropertyNameCaseInsensitive = false,保证前后端参数名大小写完全匹配,或者给服务端方法加[HubMethodName("FileUpload")]特性显式指定方法名 - 如果文件过大,调整 SignalR 的最大消息大小配置:
builder.Services.AddSignalR(options => { options.MaximumReceiveMessageSize = 10 * 1024 * 1024; // 调整为你需要的大小,比如10M });
内容的提问来源于stack exchange,提问作者Shanto Siddiq
相关产品推荐
相关产品推荐

