You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Minimal API的文件上传:C#客户端调用难题

解决Minimal API文件仓库的两个问题:C#客户端上传与检索返回额外数据

一、C#客户端调用带TenantID的文件上传接口

假设你的Minimal API上传接口定义如下(可根据实际参数位置调整):

// Minimal API 上传接口示例
app.MapPost("/files/upload/{tenantId}", async (string tenantId, IFormFile file) =>
{
    // 租户隔离存储逻辑
    var storedFileId = Guid.NewGuid().ToString();
    // 执行文件存储操作...
    return Results.Ok(new { FileId = storedFileId });
});

C#客户端使用HttpClient调用时,需通过MultipartFormDataContent构造表单数据,同时传递TenantID:

using var httpClient = new HttpClient();
var tenantId = "目标租户ID";
var filePath = @"本地文件路径";

// 构造多部分表单内容
using var content = new MultipartFormDataContent();
// 添加文件流
using var fileStream = new FileStream(filePath, FileMode.Open);
var fileContent = new StreamContent(fileStream);
fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); // 按实际文件类型调整
content.Add(fileContent, "file", Path.GetFileName(filePath));

// 发送请求(TenantID作为路由参数)
var response = await httpClient.PostAsync($"https://你的API地址/files/upload/{tenantId}", content);
response.EnsureSuccessStatusCode();

// 解析返回的文件ID
var result = await response.Content.ReadFromJsonAsync<FileUploadResult>();
Console.WriteLine($"上传成功,文件ID:{result.FileId}");

// 定义返回模型
public class FileUploadResult
{
    public string FileId { get; set; }
}

如果TenantID是通过表单参数传递(接口用[FromForm] string tenantId),需在Multipart内容中添加:

content.Add(new StringContent(tenantId), "tenantId");

二、检索接口返回文件时附带额外数据

你提到的Results.File仅返回文件内容的问题,在.NET 8之前可通过以下两种方案解决:

方案1:将元数据放入响应头(推荐)

修改检索接口,在返回文件前添加自定义响应头存储元数据:

app.MapGet("/files/{tenantId}/{fileId}", async (string tenantId, string fileId) =>
{
    var storeLocation = Path.Combine("tenants", tenantId, fileId);
    var mimeType = "application/octet-stream"; // 按实际文件类型设置

    var fileResult = Results.File(storeLocation, mimeType);
    // 添加自定义响应头
    fileResult.HttpContext.Response.Headers.Add("X-File-Id", fileId);
    fileResult.HttpContext.Response.Headers.Add("X-Tenant-Id", tenantId);
    fileResult.HttpContext.Response.Headers.Add("X-Content-Type", mimeType);

    return fileResult;
});

客户端调用时,先读取响应头再获取文件内容:

using var httpClient = new HttpClient();
var tenantId = "目标租户ID";
var fileId = "目标文件ID";

var response = await httpClient.GetAsync($"https://你的API地址/files/{tenantId}/{fileId}");
response.EnsureSuccessStatusCode();

// 读取元数据
var returnedFileId = response.Headers.GetValues("X-File-Id").FirstOrDefault();
var returnedTenantId = response.Headers.GetValues("X-Tenant-Id").FirstOrDefault();
var mimeType = response.Content.Headers.ContentType?.MediaType;

// 读取文件内容
var fileContent = await response.Content.ReadAsByteArrayAsync();
// 执行保存或处理操作...

方案2:返回包含元数据与Base64文件的JSON(仅适合小文件)

若文件体积较小,可将文件转为Base64字符串,与元数据一起返回JSON:

app.MapGet("/files/{tenantId}/{fileId}", async (string tenantId, string fileId) =>
{
    var storeLocation = Path.Combine("tenants", tenantId, fileId);
    var mimeType = "application/octet-stream";
    var fileBytes = await File.ReadAllBytesAsync(storeLocation);
    var base64Content = Convert.ToBase64String(fileBytes);

    return Results.Ok(new {
        FileId = fileId,
        TenantId = tenantId,
        MimeType = mimeType,
        FileContent = base64Content
    });
});

客户端解析后转回字节数组:

var result = await response.Content.ReadFromJsonAsync<FileRetrievalResult>();
var fileBytes = Convert.FromBase64String(result.FileContent);
// 处理文件内容...

public class FileRetrievalResult
{
    public string FileId { get; set; }
    public string TenantId { get; set; }
    public string MimeType { get; set; }
    public string FileContent { get; set; }
}

内容的提问来源于stack exchange,提问作者MisterA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 00:27:25