如何将HttpResponseMessage保存为二进制至SQLite并供用户查看?
二进制附件存储SQLite及查看实现方案
一、问题根源
你当前代码存成JSON的核心原因:API返回的不是直接的文件二进制流,而是序列化后的HttpResponseMessage JSON字符串(也就是你给出的示例内容)。这时候调用ReadAsByteArrayAsync()拿到的是JSON的字节数据,而非真实文件的二进制。
二、修正二进制存储代码
1. 定义JSON解析模型
先把API返回的JSON结构对应成C#类,方便解析文件元数据:
public class HttpResponseMessageDto { public string Version { get; set; } public ContentDto Content { get; set; } public int StatusCode { get; set; } public string ReasonPhrase { get; set; } public List<HeaderDto> Headers { get; set; } public List<HeaderDto> TrailingHeaders { get; set; } public object RequestMessage { get; set; } public bool IsSuccessStatusCode { get; set; } } public class ContentDto { public List<HeaderDto> Headers { get; set; } } public class HeaderDto { public string Key { get; set; } public List<string> Value { get; set; } }
2. 正确获取并保存文件二进制
修改请求逻辑,先解析JSON拿到文件信息,再获取真实的文件二进制流:
var getFiles = new HttpRequestMessage(HttpMethod.Get, $"{Constants.getTicketApi}/{data.Id}/Document?filename={filename}"); HttpResponseMessage fileresponse = await _httpClient.SendAsync(getFiles); if (fileresponse.IsSuccessStatusCode) { // 读取并解析API返回的JSON var responseJson = await fileresponse.Content.ReadAsStringAsync(); var responseDto = JsonSerializer.Deserialize<HttpResponseMessageDto>(responseJson); // 提取文件名和内容类型 var dispositionHeader = responseDto.Content.Headers.FirstOrDefault(h => h.Key == "Content-Disposition")?.Value.FirstOrDefault(); var fileName = dispositionHeader?.Split("filename=\"")[1].TrimEnd('"'); var contentType = responseDto.Content.Headers.FirstOrDefault(h => h.Key == "Content-Type")?.Value.FirstOrDefault(); // 重新请求获取真实文件二进制(告诉服务器返回二进制而非JSON) var fileRequest = new HttpRequestMessage(HttpMethod.Get, $"{Constants.getTicketApi}/{data.Id}/Document?filename={filename}"); fileRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType)); HttpResponseMessage fileStreamResponse = await _httpClient.SendAsync(fileRequest); if (fileStreamResponse.IsSuccessStatusCode) { var fileBytes = await fileStreamResponse.Content.ReadAsByteArrayAsync(); FilesDB file = new FilesDB { TicketId = data.Id, FileDescriptorID = fdId, Data = fileBytes, FileName = fileName, // 建议额外存储文件名和类型,方便后续查看 ContentType = contentType }; await _context.SaveData(file); } } await _context.SaveData(filedescriptor);
3. 配置SQLite表结构
确保FilesDB对应的SQLite表中,Data字段类型为BLOB(二进制大对象),用EF Core配置的话:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<FilesDB>() .Property(f => f.Data) .HasColumnType("BLOB"); }
三、实现用户打开查看功能
1. 从SQLite读取文件数据
public async Task<FilesDB> GetFileById(int fileId) { return await _context.FilesDB.FirstOrDefaultAsync(f => f.Id == fileId); }
2. 分平台实现打开逻辑
桌面端(WPF/WinForms)
var file = await GetFileById(selectedFileId); // 写入临时文件 var tempPath = Path.Combine(Path.GetTempPath(), file.FileName); File.WriteAllBytes(tempPath, file.Data); // 调用系统默认程序打开 Process.Start(new ProcessStartInfo(tempPath) { UseShellExecute = true });
移动端(Xamarin/.NET MAUI)
var file = await GetFileById(selectedFileId); // 保存到应用缓存目录 var tempFile = Path.Combine(FileSystem.CacheDirectory, file.FileName); File.WriteAllBytes(tempFile, file.Data); // 调用系统打开文件 await Launcher.OpenAsync(new OpenFileRequest { File = new ReadOnlyFile(tempFile), ContentType = file.ContentType });
Web端(ASP.NET Core)
在控制器中提供文件下载/打开接口:
[HttpGet("file/{fileId}")] public async Task<IActionResult> OpenFile(int fileId) { var file = await _context.FilesDB.FirstOrDefaultAsync(f => f.Id == fileId); if (file == null) return NotFound(); return File(file.Data, file.ContentType, file.FileName); }
前端通过链接打开:
<a href="/api/file/1" target="_blank">打开文件</a>
内容的提问来源于stack exchange,提问作者Jean Ivan Steven
相关产品推荐
相关产品推荐

