如何在最小 API 中返回多部分内容

最小 API 是一种简化的 ASP.NET Core Web API 的编程模式,它可以使用最少的代码创建 HTTP 服务。

不过,有时候我们可能需要返回不同类型的数据,比如说一个图片文件和一些文本信息,这时候该怎么办呢?.

简单实现

其实,我们可以利用 MultipartFormDataContent 类来实现这个功能,它是 MultipartContent 的一个子类,它可以存放多个 HttpContent 对象,每个对象就代表一种数据类型。我们只需要给 MultipartContent 对象设置一个 boundary 参数,就可以用它来分隔不同的数据类型。

代码示例:

app.MapGet("/GetFile", () =>
{
    // 实例化multipart表单模型
    var formData = new MultipartFormDataContent("----myio_boundary");
    // 设定文本类型表单项,使用StringContent存放字符串
    formData.Add(new StringContent("测试图片"), "desc");
    // 设定文件类型表单项,使用StreamContent存放文件流
    formData.Add(new StreamContent(new FileStream(@"demo.jpg", FileMode.Open, FileAccess.Read)), "file", "a.jpg");
 
    return formData;
});

但是,当我们运行这段代码的时候,却发现返回的结果并不是我们想要的,而是一个 JSON 对象:

[{
 "headers": [{
  "key": "Content-Type",
  "value": ["text/plain; charset=utf-8"]
 }, {
  "key": "Content-Disposition",
  "value": ["form-data; name=desc"]
 }]
}, {
 "headers": [{
  "key": "Content-Disposition",
  "value": ["form-data; name=file; filename=a.jpg; filename*=utf-8''a.jpg"]
 }]
}]

这是怎么回事呢?

原来,最小 API 并不知道如何处理 MultipartFormDataContent 类型,它只会用默认的 JSON 序列化器来处理返回值。

解决方案

要解决这个问题,我们需要自己写一个返回值处理器,它需要将 MultipartFormDataContent 对象转换成 Stream 对象,然后把 Stream 对象写入 HTTP 响应中。

代码示例:

app.MapGet("/GetFile", () =>
{
    // 实例化multipart表单模型
    var formData = new MultipartFormDataContent("----myioboundary");
    // 设定文本类型表单项,使用StringContent存放字符串
    formData.Add(new StringContent("测试图片"), "desc");
    // 设定文件类型表单项,使用StreamContent存放文件流
    formData.Add(new StreamContent(new FileStream(@"demo.jpg", FileMode.Open, FileAccess.Read)), "file", "a.jpg");

    return new MultipartFormDataContentResult(formData);
});
 
public class MultipartFormDataContentResult : IResult
{
    private readonly MultipartFormDataContent _content;

    public MultipartFormDataContentResult(MultipartFormDataContent content)
    {
        _content = content;
    }

    public async Task ExecuteAsync(HttpContext httpContext)
    {
        httpContext.Response.ContentType = _content.Headers.ContentType.ToString();
        await _content.CopyToAsync(httpContext.Response.Body);
    }
}

这样一来,我们就可以成功地返回多部分内容了。

测试

我们可以用 Postman 来发送请求,看看返回的结果是否正确:

如何在最小 API 中返回多部分内容

我们也可以用代码来获取,代码示例:

var httpClient = new HttpClient();

var responseMessage = await httpClient.GetAsync(@"http://localhost:5281/GetFile");

//需要引用 Nuget 包 Microsoft.AspNet.WebApi.Client
var multipartcontent = await responseMessage.Content.ReadAsMultipartAsync();
foreach (HttpContent content in multipartcontent.Contents)
{
    if (!string.IsNullOrEmpty(content.Headers.ContentDisposition.FileName))
    {
        Console.WriteLine($"{content.Headers.ContentDisposition.FileName} File Size:{(await content.ReadAsByteArrayAsync()).Length}");
    }
    else
    {
        Console.WriteLine($"{content.Headers.ContentDisposition.Name} = {await content.ReadAsStringAsync()}");
    }
}

输出结果如下:

desc = 测试图片
a.jpg File Size:26420

总结

通过本文,你学会了如何在最小 API 中返回多部分内容,希望对你有所帮助!