如何配置Blazor Server以支持大于28.6MB的文件上传?
嘿,我之前也踩过Blazor Server大文件上传的坑,结合你的情况,给你梳理几个关键的排查和解决方向:
1. 先改掉「一次性读入MemoryStream」的做法
这是你当前代码里最核心的问题!不管是CopyToAsync(ms)还是CreateMemoryStreamAsync,把几十MB甚至更大的文件全塞进内存,不仅会瞬间拉满服务器内存,还会触发SignalR的消息大小限制(哪怕你配置了,大内存块传递也容易卡住)。
正确的做法是流式上传,直接把客户端的文件流写到服务器的文件系统或者存储服务,跳过MemoryStream这一步:
BlazorInputFile 示例
// 直接打开客户端流,指定最大允许的流大小(比如100MB) using var clientStream = file.OpenReadStream(100 * 1024 * 1024); // 服务器端创建文件流 using var serverFileStream = new FileStream($"wwwroot/uploads/{file.Name}", FileMode.Create); // 直接流式复制,全程不占大内存 await clientStream.CopyToAsync(serverFileStream);
Tewr.Blazor.FileReader 示例
// 获取文件的流(同样避免读进内存) using var stream = await fileReader.CreateReadStreamAsync(fileRef, 100 * 1024 * 1024); using var serverFileStream = new FileStream($"wwwroot/uploads/{file.Name}", FileMode.Create); await stream.CopyToAsync(serverFileStream);
2. 补全ASP.NET Core的请求体限制配置
你之前只设置了IHttpMaxRequestBodySizeFeature,但文件上传属于multipart/form-data请求,还需要配置FormOptions的分片大小限制:
在Program.cs里添加:
services.Configure<FormOptions>(options => { // 设置最大multipart请求体大小(100MB) options.MultipartBodyLengthLimit = 100 * 1024 * 1024; // 单个文件的大小限制,和上面保持一致即可 options.MultipartBoundaryLengthLimit = 100 * 1024 * 1024; });
这个配置是针对表单上传的,默认值刚好是你提到的~28.6MB,这也是你23MB能传、更大就挂的直接原因之一。
3. 确认SignalR Hub配置的有效性
你已经加了MaximumReceiveMessageSize,但要确保配置的位置正确,并且没有被其他中间件覆盖:
// 正确的顺序:先注册Blazor服务,再配置Hub选项 services.AddServerSideBlazor() .AddHubOptions(options => { // 允许接收的最大消息大小(100MB) options.MaximumReceiveMessageSize = 100 * 1024 * 1024; // 可选:如果上传超大文件,延长超时时间避免连接断开 options.KeepAliveInterval = TimeSpan.FromMinutes(5); options.ClientTimeoutInterval = TimeSpan.FromMinutes(10); });
另外,如果你之前单独注册了SignalR服务(services.AddSignalR()),也要同步配置它的MaximumReceiveMessageSize,因为Blazor Server的底层依赖SignalR。
4. 检查组件自身的限制
- BlazorInputFile:默认有一个
MaximumFileSize限制,你在调用OpenReadStream的时候一定要传入允许的最大大小,比如file.OpenReadStream(100*1024*1024),否则会用默认值(通常是20MB左右)。 - Tewr.Blazor.FileReader:注册服务的时候可以配置全局的缓冲区大小,避免小缓冲区导致的读取阻塞:
services.AddFileReader(options => { options.MaxBufferSize = 100 * 1024 * 1024; });
5. 部署到IIS的额外配置
如果你的应用部署在IIS上,还要修改web.config,补上IIS层面的大小限制:
<configuration> <system.web> <!-- 单位是KB,100MB=102400KB --> <httpRuntime maxRequestLength="102400" /> </system.web> <system.webServer> <security> <requestFiltering> <!-- 单位是字节,100MB=104857600字节 --> <requestLimits maxAllowedContentLength="104857600" /> </requestFiltering> </security> </system.webServer> </configuration>
IIS的默认限制比ASP.NET Core更严格,漏掉这一步的话,大文件上传会直接被IIS拦截。
最后总结
按优先级来的话:
- 立刻改成流式上传,去掉MemoryStream的使用
- 配置
FormOptions的MultipartBodyLengthLimit - 确认SignalR Hub的大小和超时配置
- 检查组件自身的大小限制
- (如果用IIS)补上web.config的配置
按这个流程走,应该能解决你文件上传挂起的问题。
内容的提问来源于stack exchange,提问作者Rafal010101

