从HttpClient向webapi提交File和Json数据



我想将文件和json数据从HttpClient发送到web api服务器
我似乎无法通过有效负载访问服务器中的json,只能作为json变量。

 public class RegulationFilesController : BaseApiController
    {
        public void PostFile(RegulationFileDto dto)
        {
            //the dto is null here
        }
    }

这是客户:

   using (var client = new HttpClient())
                {
                    using (var content = new MultipartFormDataContent())
                    {
                        client.BaseAddress = new Uri(ConfigurationManager.AppSettings["ApiHost"]);
                        content.Add(new StreamContent(File.OpenRead(@"C:\Chair.png")), "Chair", "Chair.png");
                        var parameters = new RegulationFileDto
                        {
                            ExternalAccountId = "1234",
                        };
                        JavaScriptSerializer serializer = new JavaScriptSerializer();
                        content.Add(new StringContent(serializer.Serialize(parameters), Encoding.UTF8, "application/json"));
                            var resTask = client.PostAsync("api/RegulationFiles", content); //?ApiKey=24Option_key
                            resTask.Wait();
                            resTask.ContinueWith(async responseTask =>
                            {
                                var res = await responseTask.Result.Content.ReadAsStringAsync();

                            }
                                );
                    }
                }

此示例将起作用:C中的HttpClient Multipart Form Post#但仅通过表单数据而不是有效载荷。

你能建议如何在同一请求下访问该文件和提交的json以及该文件吗?

感谢

我尝试了许多不同的方法来提交文件数据和元数据,这是我发现的最好的方法:

不要使用MultipartFormDataContent,只对文件数据使用StreamContent。通过这种方式,你可以流式传输文件上传,这样你就不会占用服务器上太多的RAM。MultipartFormDataContent要求您将整个请求加载到内存中,然后将文件保存到某个本地存储中。通过流式传输,您还可以将流复制到其他位置,如Azure存储容器。

这解决了二进制数据的问题,现在也解决了元数据的问题。为此,请使用自定义标头并将JSON序列化为该标头。您的控制器可以读取自定义标头,并将其反序列化为元数据dto。标头有大小限制,请参阅此处(8-16KB),这是一个大量的数据。如果您需要更多的空间,您可以执行两个单独的请求,一个用于POST最低需求,然后一个PATCH用于更新任何需要超过标头容量的属性。

样本代码:

public class RegulationFilesController : BaseApiController
{
    public async Task<IHttpActionResult> Post()
    {
        var isMultipart = this.Request.Content.IsMimeMultipartContent();
        if (isMultipart)
        {
            return this.BadRequest("Only binary uploads are accepted.");
        }
        var headerDto = this.GetJsonDataHeader<RegulationFileDto>();
        if(headerDto == null)
        {
            return this.BadRequest("Missing X-JsonData header.");
        }
        using (var stream = await this.Request.Content.ReadAsStreamAsync())
        {
            if (stream == null || stream.Length == 0)
            {
                return this.BadRequest("Invalid binary data.");
            }
            //save stream to disk or copy to another stream
            var model = new RegulationFile(headerDto);
            //save your model to the database
            var dto = new RegulationFileDto(model);
            var uri = new Uri("NEW URI HERE");
            return this.Created(uri, dto);
        }
    }
    private T GetJsonDataHeader<T>()
    {
        IEnumerable<string> headerCollection;
        if (!this.Request.Headers.TryGetValues("X-JsonData", out headerCollection))
        {
            return default(T);
        }
        var headerItems = headerCollection.ToList();
        if (headerItems.Count() != 1)
        {
            return default(T);
        }
        var meta = headerItems.FirstOrDefault();
        return !string.IsNullOrWhiteSpace(meta) ? JsonConvert.DeserializeObject<T>(meta) : default(T);
    }
}

最新更新