【问题标题】:C# HttpClient 4.5 multipart/form-data uploadC# HttpClient 4.5 多部分/表单数据上传
【发布时间】:2013-05-01 06:17:53
【问题描述】:

有谁知道如何在.Net 4.5 中使用HttpClientmultipart/form-data 上传?

我在互联网上找不到任何示例。

【问题讨论】:

  • 我试过了,但我不知道如何启动它。我将 byteArray 添加到内容等等。我需要一些帮助。
  • 你可以看看这个帖子的答案。 (带代理设置)stackoverflow.com/a/50462636/2123797

标签: c# upload .net-4.5 multipartform-data dotnet-httpclient


【解决方案1】:

我的结果如下所示:

public static async Task<string> Upload(byte[] image)
{
     using (var client = new HttpClient())
     {
         using (var content =
             new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
         {
             content.Add(new StreamContent(new MemoryStream(image)), "bilddatei", "upload.jpg");

              using (
                 var message =
                     await client.PostAsync("http://www.directupload.net/index.php?mode=upload", content))
              {
                  var input = await message.Content.ReadAsStringAsync();

                  return !string.IsNullOrWhiteSpace(input) ? Regex.Match(input, @"http://\w*\.directupload\.net/images/\d*/\w*\.[a-z]{3}").Value : null;
              }
          }
     }
}

【讨论】:

  • 哇,将大文件上传到 REST API 时执行此操作要简单得多。我不喜欢评论感谢,但谢谢。它适用于 Windows Phone 8。
  • 此代码对我来说失败,因为传递给new MultipartFormDataContent(...) 的边界字符串包含无效的边界字符(可能是“/”分隔符)。没有错误,只是没有文件发布到服务器 - 在我的情况下,API 控制器中的 Context.Request.Files.Count = 0。可能只是Nancy 问题,但我建议改用DateTime.Now.Ticks.ToString("x") 之类的东西。
  • @MauricioAviles,您的链接已损坏。我发现这个解释得很好:aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
  • 如果您收到错误:“找不到上传的文件”,请尝试将keyfileName 参数添加到content ( bilddateiupload.jpg 在本例中)。
  • @KevinHarker,重读第二个链接。不配置 HttpClient 的段落是指之前的设计。这很容易混淆。基本上,使用 IHttpClientFactory,HttpClient Dispose 并没有真正做任何事情 (stackoverflow.com/a/54326424/476048),内部处理程序由 HttpClientFactory 管理。
【解决方案2】:

它或多或少像这样工作(使用图像/jpg文件的示例):

async public Task<HttpResponseMessage> UploadImage(string url, byte[] ImageData)
{
    var requestContent = new MultipartFormDataContent(); 
    //    here you can specify boundary if you need---^
    var imageContent = new ByteArrayContent(ImageData);
    imageContent.Headers.ContentType = 
        MediaTypeHeaderValue.Parse("image/jpeg");

    requestContent.Add(imageContent, "image", "image.jpg");

    return await client.PostAsync(url, requestContent);
}

(你可以requestContent.Add() 随便你,看看HttpContent descendant 看看可以传入的类型)

完成后,您会在HttpResponseMessage.Content 中找到响应内容,您可以使用HttpContent.ReadAs*Async 来消费。

【讨论】:

  • 啊谢谢// here you can specify boundary if you need---^ :)
  • 为什么这不起作用?公共异步任务 SendImage(byte[] foto) { var requestContent = new MultipartFormDataContent(); var imageContent = new ByteArrayContent(foto); imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg"); requestContent.Add(imageContent, "foto", "foto.jpg");字符串 url = "myAddress/myWS/api/Home/SendImage?foto=";等待 _client.PostAsync(url, requestContent);返回“确定”; }
  • 第一行的async和最后一行之前的await是不必要的。
  • 对于大文件,在请求中添加流内容而不是字节数组。
  • @WDRust,使用字节数组,您首先将整个文件加载到内存然后发送。使用流内容,使用缓冲区读取和发送文件,这在内存方面更有效。
【解决方案3】:

这是一个如何通过 HTTPClient 使用 MultipartFormDataContent 发布字符串和文件流的示例。需要为每个 HTTPContent 指定 Content-Disposition 和 Content-Type:

这是我的例子。希望对您有所帮助:

private static void Upload()
{
    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Add("User-Agent", "CBS Brightcove API Service");

        using (var content = new MultipartFormDataContent())
        {
            var path = @"C:\B2BAssetRoot\files\596086\596086.1.mp4";

            string assetName = Path.GetFileName(path);

            var request = new HTTPBrightCoveRequest()
                {
                    Method = "create_video",
                    Parameters = new Params()
                        {
                            CreateMultipleRenditions = "true",
                            EncodeTo = EncodeTo.Mp4.ToString().ToUpper(),
                            Token = "x8sLalfXacgn-4CzhTBm7uaCxVAPjvKqTf1oXpwLVYYoCkejZUsYtg..",
                            Video = new Video()
                                {
                                    Name = assetName,
                                    ReferenceId = Guid.NewGuid().ToString(),
                                    ShortDescription = assetName
                                }
                        }
                };

            //Content-Disposition: form-data; name="json"
            var stringContent = new StringContent(JsonConvert.SerializeObject(request));
            stringContent.Headers.Add("Content-Disposition", "form-data; name=\"json\"");
            content.Add(stringContent, "json");

            FileStream fs = File.OpenRead(path);

            var streamContent = new StreamContent(fs);
            streamContent.Headers.Add("Content-Type", "application/octet-stream");
            //Content-Disposition: form-data; name="file"; filename="C:\B2BAssetRoot\files\596090\596090.1.mp4";
            streamContent.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"" + Path.GetFileName(path) + "\"");
            content.Add(streamContent, "file", Path.GetFileName(path));

            //content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");

            Task<HttpResponseMessage> message = client.PostAsync("http://api.brightcove.com/services/post", content);

            var input = message.Result.Content.ReadAsStringAsync();
            Console.WriteLine(input.Result);
            Console.Read();
        }
    }
}

【讨论】:

  • @Trout 你不知道你的代码是如何让我今天如此开心的! +1
  • 这是完整的答案。
  • 我知道我们不应该评论感谢信。但这就是我见过的关于如何使用MultipartFormDataContent 的最佳代码。向你致敬,先生
  • 同意。这是包含 json 字符串和文件作为有效负载内容一部分的唯一答案。
  • 我在没有Content-TypeContent-Disposition 的计算机(win7 sp1,IIS 7.5)上测试没问题,但是在Server 2008 R2(IIS 7.5)上找不到文件,这很奇怪。所以我作为答案。
【解决方案4】:

这是另一个关于如何使用HttpClient 上传multipart/form-data 的示例。

它将文件上传到 REST API 并包含文件本身(例如 JPG)和其他 API 参数。文件通过FileStream直接从本地磁盘上传。

请参阅here 了解完整示例,包括额外的 API 特定逻辑。

public static async Task UploadFileAsync(string token, string path, string channels)
{
    // we need to send a request with multipart/form-data
    var multiForm = new MultipartFormDataContent();

    // add API method parameters
    multiForm.Add(new StringContent(token), "token");
    multiForm.Add(new StringContent(channels), "channels");

    // add file and directly upload it
    FileStream fs = File.OpenRead(path);
    multiForm.Add(new StreamContent(fs), "file", Path.GetFileName(path));

    // send request to API
    var url = "https://slack.com/api/files.upload";
    var response = await client.PostAsync(url, multiForm);
}

【讨论】:

    【解决方案5】:

    试试这对我有用。

    private static async Task<object> Upload(string actionUrl)
    {
        Image newImage = Image.FromFile(@"Absolute Path of image");
        ImageConverter _imageConverter = new ImageConverter();
        byte[] paramFileStream= (byte[])_imageConverter.ConvertTo(newImage, typeof(byte[]));
    
        var formContent = new MultipartFormDataContent
        {
            // Send form text values here
            {new StringContent("value1"),"key1"},
            {new StringContent("value2"),"key2" },
            // Send Image Here
            {new StreamContent(new MemoryStream(paramFileStream)),"imagekey","filename.jpg"}
        };
    
        var myHttpClient = new HttpClient();
        var response = await myHttpClient.PostAsync(actionUrl.ToString(), formContent);
        string stringContent = await response.Content.ReadAsStringAsync();
    
        return response;
    }
    

    【讨论】:

    • 完美无瑕。正是我在 .NET Core TestServer.CreatClient() 数据+文件上传集成测试场景中寻找的内容。
    • 如果方法是HTTPGET如何传递formcontent
    • @MBG GET 请求按照惯例通常没有请求正文,因此您不能使用 GET 上传文件(或者除非您发送到的服务器非常不寻常,否则不能上传 - 大多数网络服务器不会期望它或支持它),因为没有请求正文包含文件或随附的表单数据。我相信从技术上讲,理论上没有什么可以阻止这样做,只是几乎所有 HTTP 实现的约定在语义上都是这样,GET 主要用于检索信息(而不是发送),因此没有 body
    • .Net 5 - 你的简单解决方案非常适合我!
    • 完美!为我工作。我遇到的大多数 API 都需要所有 3 个参数才能接受新的 StreamContent。
    【解决方案6】:

    这是一个对我有用的完整示例。请求中的boundary 值由.NET 自动添加。

    var url = "http://localhost/api/v1/yourendpointhere";
    var filePath = @"C:\path\to\image.jpg";
    
    HttpClient httpClient = new HttpClient();
    MultipartFormDataContent form = new MultipartFormDataContent();
    
    FileStream fs = File.OpenRead(filePath);
    var streamContent = new StreamContent(fs);
    
    var imageContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
    imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
    
    form.Add(imageContent, "image", Path.GetFileName(filePath));
    var response = httpClient.PostAsync(url, form).Result;
    

    【讨论】:

    【解决方案7】:

    预加载器 Dotnet 3.0 Core 示例

    ProgressMessageHandler processMessageHander = new ProgressMessageHandler();
    
    processMessageHander.HttpSendProgress += (s, e) =>
    {
        if (e.ProgressPercentage > 0)
        {
            ProgressPercentage = e.ProgressPercentage;
            TotalBytes = e.TotalBytes;
            progressAction?.Invoke(progressFile);
        }
    };
    
    using (var client = HttpClientFactory.Create(processMessageHander))
    {
        var uri = new Uri(transfer.BackEndUrl);
        client.DefaultRequestHeaders.Authorization =
        new AuthenticationHeaderValue("Bearer", AccessToken);
    
        using (MultipartFormDataContent multiForm = new MultipartFormDataContent())
        {
            multiForm.Add(new StringContent(FileId), "FileId");
            multiForm.Add(new StringContent(FileName), "FileName");
            string hash = "";
    
            using (MD5 md5Hash = MD5.Create())
            {
                var sb = new StringBuilder();
                foreach (var data in md5Hash.ComputeHash(File.ReadAllBytes(FullName)))
                {
                    sb.Append(data.ToString("x2"));
                }
                hash = result.ToString();
            }
            multiForm.Add(new StringContent(hash), "Hash");
    
            using (FileStream fs = File.OpenRead(FullName))
            {
                multiForm.Add(new StreamContent(fs), "file", Path.GetFileName(FullName));
                var response = await client.PostAsync(uri, multiForm);
                progressFile.Message = response.ToString();
    
                if (response.IsSuccessStatusCode) {
                    progressAction?.Invoke(progressFile);
                } else {
                    progressErrorAction?.Invoke(progressFile);
                }
                response.EnsureSuccessStatusCode();
            }
        }
    }
    

    【讨论】:

      【解决方案8】:

      我正在添加一个代码 sn-p,它显示了如何将文件发布到已通过 DELETE http 动词公开的 API。这不是使用 DELETE http 动词上传文件的常见情况,但这是允许的。我假设 Windows NTLM 身份验证用于授权调用。

      可能面临的问题是HttpClient.DeleteAsync 方法的所有重载都没有HttpContent 的参数,我们在PostAsync 方法中获取它的方式

      var requestUri = new Uri("http://UrlOfTheApi");
      using (var streamToPost = new MemoryStream("C:\temp.txt"))
      using (var fileStreamContent = new StreamContent(streamToPost))
      using (var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true })
      using (var httpClient = new HttpClient(httpClientHandler, true))
      using (var requestMessage = new HttpRequestMessage(HttpMethod.Delete, requestUri))
      using (var formDataContent = new MultipartFormDataContent())
      {
          formDataContent.Add(fileStreamContent, "myFile", "temp.txt");
          requestMessage.Content = formDataContent;
          var response = httpClient.SendAsync(requestMessage).GetAwaiter().GetResult();
          
          if (response.IsSuccessStatusCode)
          {
              // File upload was successfull
          }
          else
          {
              var erroResult = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
              throw new Exception("Error on the server : " + erroResult);
          }
      }
      

      您需要在 C# 文件的顶部使用以下命名空间:

      using System;
      using System.Net;
      using System.IO;
      using System.Net.Http;
      

      P.S. 您在上面的代码 sn-p 中看到了许多 using 块(IDisposable 模式),看起来不太干净。不幸的是,using 构造的语法不支持在单个语句中初始化多个变量。

      【讨论】:

        【解决方案9】:
        X509Certificate clientKey1 = null;
        clientKey1 = new X509Certificate(AppSetting["certificatePath"],
        AppSetting["pswd"]);
        string url = "https://EndPointAddress";
        FileStream fs = File.OpenRead(FilePath);
        var streamContent = new StreamContent(fs);
        
        var FileContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
        FileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("ContentType");
        var handler = new WebRequestHandler();
        
        
        handler.ClientCertificateOptions = ClientCertificateOption.Manual;
        handler.ClientCertificates.Add(clientKey1);
        handler.ServerCertificateValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) =>
        {
            return true;
        };
        
        
        using (var client = new HttpClient(handler))
        {
            // Post it
            HttpResponseMessage httpResponseMessage = client.PostAsync(url, FileContent).Result;
        
            if (!httpResponseMessage.IsSuccessStatusCode)
            {
                string ss = httpResponseMessage.StatusCode.ToString();
            }
        }
        

        【讨论】:

        • 此方案用于通过安全证书将文件上传到 API 站点
        【解决方案10】:
        public async Task<object> PassImageWithText(IFormFile files)
        {
            byte[] data;
            string result = "";
            ByteArrayContent bytes;
        
            MultipartFormDataContent multiForm = new MultipartFormDataContent();
        
            try
            {
                using (var client = new HttpClient())
                {
                    using (var br = new BinaryReader(files.OpenReadStream()))
                    {
                        data = br.ReadBytes((int)files.OpenReadStream().Length);
                    }
        
                    bytes = new ByteArrayContent(data);
                    multiForm.Add(bytes, "files", files.FileName);
                    multiForm.Add(new StringContent("value1"), "key1");
                    multiForm.Add(new StringContent("value2"), "key2");
        
                    var res = await client.PostAsync(_MEDIA_ADD_IMG_URL, multiForm);
                }
            }
            catch (Exception e)
            {
                throw new Exception(e.ToString());
            }
        
            return result;
        }
        

        【讨论】:

        • 您可以通过评论您编写的代码来改进您的答案
        • OK msrd!对不起我的新手。我试着写一个清晰的代码,比如“Erik Kalkoke”,我喜欢它。我将分享我的代码,例如在服务器节点 1 上通过 IFormFile 接收图像,并通过类 [MultipartFormDataContent] 增加一些文本传递到服务器节点 2 哦!最后一行是这样的。结果 = 等待 res.Content.ReadAsStringAsync();
        • 很好的解决方案,不过。 +1
        猜你喜欢
        • 1970-01-01
        • 2020-05-27
        • 1970-01-01
        • 1970-01-01
        • 2016-11-03
        • 2018-03-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多