C # HttpClient 4.5 multipart / unggah formulir data

145

Adakah yang tahu cara menggunakan HttpClientin .Net 4.5 dengan multipart/form-datamengunggah?

Saya tidak dapat menemukan contoh di internet.

ident
sumber
1
Saya mencoba tetapi saya tidak tahu bagaimana memulainya .. di mana saya menambahkan byteArray ke konten dan sebagainya. Saya butuh semacam bantuan awal.
identifikasi
Anda dapat melihat jawaban posting ini. (Dengan pengaturan Proxy) stackoverflow.com/a/50462636/2123797
Ergin Çelik

Jawaban:

156

hasil saya terlihat seperti ini:

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;
              }
          }
     }
}
ident
sumber
6
Wow, jauh lebih mudah untuk melakukan ini ketika mengunggah file besar ke REST API. Saya tidak suka berkomentar untuk terima kasih, tapi terima kasih. Ini portabel untuk Windows Phone 8.
Léon Pelletier
1
Kode ini gagal bagi saya karena string batas yang diteruskan new MultipartFormDataContent(...)mengandung karakter batas yang tidak valid (mungkin pemisah "/"). Tidak ada kesalahan, hanya tidak ada file yang diposting ke server - dalam kasus saya, Context.Request.Files.Count = 0 di pengontrol API. Mungkin hanya Nancymasalah, tapi saya sarankan menggunakan sesuatu seperti DateTime.Now.Ticks.ToString("x")gantinya.
Dunc
7
@MauricioAviles, tautan Anda rusak. Saya menemukan ini yang menjelaskannya dengan baik: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Kevin Harker
1
Jika Anda mendapatkan error: " Uploaded file (s) tidak ditemukan " mencoba untuk menambahkan keydan fileNameparameter untuk content( bilddatei dan upload.jpg dalam contoh ini).
jhhwilliams
1
@KevinHarker, Baca kembali tautan kedua itu. Paragraf yang berbicara tentang tidak membuang HttpClient mengacu pada desain sebelumnya. Mudah membingungkan. Pada dasarnya, dengan IHttpClientFactory, Buang HttpClient tidak benar-benar melakukan apa-apa ( stackoverflow.com/a/54326424/476048 ) dan penangan internal dikelola oleh HttpClientFactory.
Berin Loritsch
83

Ini berfungsi kurang lebih seperti ini (misalnya menggunakan file gambar / 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);
}

(Anda dapat requestContent.Add()apa pun yang Anda inginkan, lihat keturunan HttpContent untuk melihat tipe yang tersedia untuk dilewati)

Setelah selesai, Anda akan menemukan konten respons di dalamnya HttpResponseMessage.Contentyang dapat Anda konsumsi HttpContent.ReadAs*Async.

WDRust
sumber
2
Ahhh terima kasih atas // here you can specify boundary if you need---^:)
sfarbota
1
mengapa ini tidak berhasil? public async Task <string> SendImage (byte [] foto) {var requestContent = new MultipartFormDataContent (); var imageContent = ByteArrayContent (foto) baru; imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse ("image / jpeg"); requestContent.Add (imageContent, "foto", "foto.jpg"); string url = " myAddress / myWS / api / Beranda / SendImage? foto = "; tunggu _client.PostAsync (url, requestContent); kembalikan "ok"; }
atapi19
1
asyncdi baris pertama dan awaitdi baris sebelum yang terakhir tidak perlu.
1valdis
Untuk file besar, tambahkan konten stream ke permintaan daripada array byte.
Elisabeth
1
@ WDRust, dengan array byte, pertama-tama Anda memuat seluruh file ke memori dan kemudian mengirimkannya. Dengan konten streaming, file dibaca dan dikirim menggunakan buffer, yang lebih efisien dalam hal memori.
Josef Bláha
53

Ini adalah contoh cara memposting string dan aliran file dengan HTTPClient menggunakan MultipartFormDataContent. Disposisi Konten dan Tipe Konten perlu ditentukan untuk setiap konten HTTPC:

Inilah contoh saya. Semoga ini bisa membantu:

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();
        }
    }
}
Johnny Chu
sumber
11
@Trout Anda tidak tahu bagaimana kode Anda membuat saya sangat bahagia hari ini! +1
Pinch
6
Inilah jawaban lengkapnya.
VK
2
Saya tahu kita tidak seharusnya mengomentari surat ucapan terima kasih. Tapi ini di sini adalah kode terbaik yang pernah saya lihat tentang cara menggunakan MultipartFormDataContent. Salam kepada Anda, Tuan
sebagomez
Sepakat. Ini adalah satu-satunya jawaban yang menyertakan string dan file json sebagai bagian dari konten payload.
frostshoxx
Saya menguji di komputer saya (win7 sp1, IIS 7.5) tanpa Content-Typedan Content-DispositionOK, tetapi pada Server 2008 R2 (IIS 7.5) tidak dapat menemukan file, itu aneh. Jadi saya lakukan sebagai jawabannya.
chengzi
18

Berikut adalah contoh lain tentang cara menggunakan HttpClientuntuk mengunggah a multipart/form-data.

Ini mengunggah file ke REST API dan menyertakan file itu sendiri (misalnya JPG) dan parameter API tambahan. File langsung diunggah dari disk lokal melalui FileStream.

Lihat di sini untuk contoh lengkap termasuk tambahan logika spesifik 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);
}
Erik Kalkoken
sumber
12

Coba ini bekerja untuk saya.

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;
}
Wisnu Kumar
sumber
Sempurna. Persis apa yang saya cari dalam TestServer.CreatClient()skenario .NET Core dari tes integrasi untuk unggahan data + file.
Vedran Mandić
jika metodenya adalah HTTPGET bagaimana cara menyampaikan konten form
MBG
@MBG GET permintaan biasanya tidak memiliki badan permintaan dengan konvensi, jadi Anda tidak dapat mengunggah file menggunakan GET (atau tidak kecuali server yang Anda kirim sangat tidak biasa - sebagian besar webservers tidak mengharapkan atau mendukungnya) , karena tidak ada badan permintaan untuk menyertakan file atau data formulir yang menyertainya. Saya percaya bahwa secara teknis tidak ada yang dapat mencegah hal ini dilakukan secara teori, hanya saja konvensi di hampir semua implementasi HTTP adalah bahwa secara semantik, GET terutama untuk mengambil informasi (daripada mengirim) sehingga tidak memiliki badan
ADyson
9

Ini contoh lengkap yang bekerja untuk saya. The boundarynilai dalam permintaan ditambahkan secara otomatis oleh 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;
nthpixel
sumber
Bagaimana kami bisa mengirim token dengan ini? Silakan lihat ini: stackoverflow.com/questions/48295877/…
@Softlion - Saya mengalami masalah TIDAK memuatnya ke dalam memori sebelum mengirim. Jika Anda tahu cara yang lebih baik, silakan posting di sini: stackoverflow.com/questions/52446969/…
emery.noel
1

Contoh dengan preloader 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();
        }
    }
}
D. Oleg
sumber
1
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();
    }
}
Rajenthiran T
sumber
Skenario ini digunakan untuk mengunggah file ke situs API dengan sertifikat keamanan
Rajenthiran T
0

Saya menambahkan cuplikan kode yang menunjukkan cara memposting file ke API yang telah diekspos di DELETE http verb. Ini bukan kasus umum untuk mengunggah file dengan DELETE http verb tetapi diizinkan. Saya berasumsi otentikasi Windows NTLM untuk otorisasi panggilan.

Masalah yang mungkin dihadapi adalah bahwa semua kelebihan HttpClient.DeleteAsyncmetode tidak memiliki parameter untuk HttpContentcara kita mendapatkannya dalam PostAsyncmetode

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);
    }
}

Anda perlu ruang nama di bawah ini di bagian atas file C # Anda:

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

PS Maaf tentang begitu banyak menggunakan blok (pola IDisposable) dalam kode saya. Sayangnya, sintaks menggunakan konstruk C # tidak mendukung inisialisasi beberapa variabel dalam satu pernyataan.

RBT
sumber
-3
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;
}
Jack The Ripper
sumber
Anda dapat meningkatkan jawaban Anda dengan mengomentari kode yang Anda tulis
msrd0
Oke msrd! Maaf tentang pemula saya. Saya mencoba untuk meletakkan kode yang jelas seperti "Erik Kalkoke", saya menyukainya. saya akan membagikan kode saya seperti menerima gambar oleh IFormFile di server node 1 dan meneruskan ke server node 2 dengan menambah beberapa teks melalui kelas [MultipartFormDataContent] Oh! baris terakhir seperti ini. hasil = menunggu res.Content.ReadAsStringAsync ();
Jack The Ripper