在 .NET Core 中使用 HttpClient 发送包含附加数据的文件列表

Sending list of files with additional data using HttpClient in .NET Core

我正在使用微服务架构,在API网关中,我收到一个请求,我想将包含List<PictureItemDto> pictures的请求发送到Attachment Microservice并存储图片信息.

我在 GatewayAttachment MicroService 中都有这些模型 类:

public class PictureDto
{
    public List<PictureItemDto> pictures { get; set; }
}

public class PictureItemDto
{
    public string seoFilename { get; set; }
    public string altAttribute { get; set; }
    public string titleAttribute { get; set; } 
    public IFormFile file { get; set; }
}

这就是我将数据从 API gateway 发送到 Attachment MicroService 的方式:

public async Task<bool> Create(List<PictureItemDto> postPictures)
{
    MultipartFormDataContent formDataContent = new MultipartFormDataContent();

    for (int i = 0; i < postPictures.Count; i++)
    {
        var item = postPictures[i];
        formDataContent.Add(new StringContent(item.seoFilename), $"pictures[{i}].seoFilename");
        formDataContent.Add(new StringContent(item.altAttribute), $"pictures[{i}].altAttribute");
        formDataContent.Add(new StringContent(item.titleAttribute), $"pictures[{i}].titleAttribute");

        StreamContent fileContent = new(item.file.OpenReadStream())
                      {
                          Headers =
                              {
                                  ContentLength =  item.file.Length,
                                  ContentType = new MediaTypeHeaderValue(item.file.ContentType)
                              }
                      };

        formDataContent.Add(fileContent, $"pictures[{i}].file", item.file.FileName);
    }

    var result = await _httpClient.PostAsync($"{_urlsOptions.AttachmentUrl}", formDataContent);

    return (result.StatusCode == HttpStatusCode.OK) ? true : false;
}

我的问题是 nullCreatePostPictures 操作中接收到数据(此操作在 attachment microservice 中):

[HttpPost("create")]
public async Task<IActionResult> CreatePostPictures([FromForm]PictureDto dto)
{
    return Ok();
}

这是我发送的 curl :

curl --location --request POST 'http://localhost:80/api/Post?api-version=1.0' \
--header 'accept: */*' \
--header 'api-version: 1.0' \
--header 'Authorization: Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJrYXZlaEBnbWFpbC5jb20iLCJqdGkiOiJlYjhkZmIyMy0wYTAxLTQzOWEtOWM1NS01Y2NmY2I2NmY3YzgiLCJ1bmlxdWVfbmFtZSI6ImthdmVoQGd' \
--form 'postPictures[0].titleAttribute="titleAttribute"' \
--form 'postPictures[0].seoFilename="seoFilename"' \
--form 'postPictures[0].altAttribute="altAttribute"' \
--form 'postPictures[0].File=@"/F:/Photos/WallPapers Pack 2011/Series 2/1024x768/WP2011.2 1024x768 (8).jpg"' \
--form 'postPictures[1].titleAttribute="titleAttribute1"' \
--form 'postPictures[1].seoFilename="seoFilename1"' \
--form 'postPictures[1].altAttribute="altAttribute1"'
--form 'postPictures[1].File=@"/F:/Photos/WallPapers Pack 2011/Series 2/1024x768/WP2011.2 1024x768 (6).jpg"' \

我终于通过将 IFormFile 转换为 Base64String 并将其转换回 IFormFile 解决了这个问题:

首先我添加两个新的 PropertiesPictureItemDto class :

public class PictureItemDto
{
    public string seoFilename { get; set; }
    public string altAttribute { get; set; }
    public string titleAttribute { get; set; } 
    public IFormFile file { get; set; }
    
    // New
    public string Base64File { get; set; }
    public string ContentType { get; set; }
}

然后在 API GatewayRequest 收到的文件应该转换为 Base64String

  public async Task<bool> Create(List<PictureItemDto> postPictures)
        {
            var i = 0;
            foreach (var file in postPictures.Select(f => f.File))
            {
                if (file.Length > 0)
                {
                    using MemoryStream ms = new();
                    file.CopyTo(ms);
                    var fileBytes = ms.ToArray();
                    postPictures[i].Base64File = Convert.ToBase64String(fileBytes);
                    postPictures[i].ContentType = file.ContentType;
                    postPictures[i].File = null;
                    i++;
                }
            }

            JsonContent content = JsonContent.Create(postPictures);

            HttpResponseMessage response = await _httpClient.PostAsync($"{_urlsOptions.AttachmentUrl}{UrlsOptions.Attachment.EntityContentController.CreatePostPictures()}", content);
            return (response.StatusCode == HttpStatusCode.OK) ? true : false;
        }

然后在 Attachment Microservice 中我接收数据并将其转换回 IFormFile :

  [HttpPost("create")]
  public async Task<IActionResult> CreatePostPictures([FromBody] List<PictureItemDto> models)
  {
            List<IFormFile> formFiles = new List<IFormFile>();
            foreach (var item in models)
            {
                byte[] bytes = Convert.FromBase64String(item.Base64File);
                MemoryStream stream = new(bytes);

                //item.File = new FormFile(stream, 0, bytes.Length, item.SeoFilename, item.SeoFilename);
                item.File = new FormFile(stream, 0, stream.Length, null, item.SeoFilename)
                {
                    Headers = new HeaderDictionary(),
                    ContentType = item.ContentType
                };
            }
   }