Blazor Server:从网络共享加载图片到MemoryStream及API调用方案
解决方案
更简便的实现方式:直接在服务层访问网络共享
Blazor Server 运行在服务器端,代码执行权限等同于 IIS 应用池身份,因此可以跳过 API 层,直接在服务类中读取网络共享文件,无需通过 HttpClient 调用接口,这是最直接高效的方案。
步骤1:创建图片操作服务
定义服务接口和实现类,封装网络共享文件的读取逻辑:
public interface IPictureService { Task<List<MemoryStream>> GetPicturesFromShareAsync(List<int> pictureIds); // 可扩展增删同步数据库等方法 } public class PictureService : IPictureService { private readonly string _sharePath = @"\\server\share\folder"; private readonly YourDbContext _dbContext; public PictureService(YourDbContext dbContext) { _dbContext = dbContext; } public async Task<List<MemoryStream>> GetPicturesFromShareAsync(List<int> pictureIds) { var pictureStreams = new List<MemoryStream>(); // 从数据库获取对应图片的文件名 var pictures = await _dbContext.Pictures .Where(p => pictureIds.Contains(p.Id)) .ToListAsync(); foreach (var pic in pictures) { var filePath = Path.Combine(_sharePath, pic.FileName); if (!File.Exists(filePath)) continue; // 读取文件到MemoryStream using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); var memoryStream = new MemoryStream(); await fileStream.CopyToAsync(memoryStream); memoryStream.Position = 0; // 重置流位置以便后续读取 pictureStreams.Add(memoryStream); } return pictureStreams; } }
步骤2:注册服务
在 Program.cs(.NET 5)中注册服务:
builder.Services.AddScoped<IPictureService, PictureService>();
步骤3:在Blazor页面中使用
注入服务后直接调用,同时处理资源释放:
@inject IPictureService PictureService @implements IDisposable <DxWizard ...> <!-- 向导内容:展示图片等操作 --> </DxWizard> @code { private List<MemoryStream> _pictureStreams; protected override async Task OnInitializedAsync() { // 假设从数据库获取需要加载的图片ID列表 var pictureIds = await GetTargetPictureIdsAsync(); _pictureStreams = await PictureService.GetPicturesFromShareAsync(pictureIds); } // 组件销毁时释放MemoryStream资源,避免内存泄漏 public void Dispose() { if (_pictureStreams != null) { foreach (var stream in _pictureStreams) { stream.Dispose(); } _pictureStreams.Clear(); } } }
关键注意事项
- 权限配置:确保 IIS 应用池的运行身份(如域账户、本地系统账户)拥有网络共享文件夹的读取权限,否则会出现访问拒绝错误。
- 资源释放:必须在组件销毁时手动释放
MemoryStream,避免内存泄漏。
若坚持使用API控制器+HttpClient方案:正确调用方式
如果需要通过API层解耦,可按以下步骤修复调用问题:
步骤1:确保API路由正确
检查 UploadController 中的 DownloadBDPicture 方法路由,示例:
[ApiController] [Route("api/[controller]")] public class UploadController : ControllerBase { private readonly string _sharePath = @"\\server\share\folder"; private readonly YourDbContext _dbContext; public UploadController(YourDbContext dbContext) { _dbContext = dbContext; } [HttpGet("download/{pictureId}")] public async Task<IActionResult> DownloadBDPicture(int pictureId) { var picture = await _dbContext.Pictures.FindAsync(pictureId); if (picture == null) return NotFound(); var filePath = Path.Combine(_sharePath, picture.FileName); if (!File.Exists(filePath)) return NotFound(); var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read); return File(stream, "image/jpeg", picture.FileName); // 根据实际图片类型调整MIME类型 } }
步骤2:在Blazor页面中正确调用API
注入 HttpClient 和 NavigationManager,构建绝对URI后调用:
@inject HttpClient Http @inject NavigationManager NavManager @implements IDisposable <DxWizard ...> <!-- 向导内容 --> </DxWizard> @code { private List<MemoryStream> _pictureStreams; protected override async Task OnInitializedAsync() { var pictureIds = await GetTargetPictureIdsAsync(); _pictureStreams = new List<MemoryStream>(); foreach (var id in pictureIds) { // 构建API的绝对URL,解决相对路径调用失败问题 var apiUrl = NavManager.ToAbsoluteUri($"/api/upload/download/{id}"); // 获取响应流并转换为MemoryStream using var responseStream = await Http.GetStreamAsync(apiUrl); var memoryStream = new MemoryStream(); await responseStream.CopyToAsync(memoryStream); memoryStream.Position = 0; _pictureStreams.Add(memoryStream); } } public void Dispose() { // 释放资源逻辑同前 if (_pictureStreams != null) { foreach (var stream in _pictureStreams) stream.Dispose(); _pictureStreams.Clear(); } } }
关键修复点
- 绝对URI构建:使用
NavigationManager.ToAbsoluteUri将相对API路径转换为绝对URL,解决HttpClient调用时的URI无效问题。 - 流处理:确保将响应流复制到
MemoryStream后重置位置,否则后续读取会从流末尾开始。
内容的提问来源于stack exchange,提问作者yooz
相关产品推荐
相关产品推荐

