C # HttpClient 4.5 çok parçalı / form verisi yükleme


146

Herkes HttpClient.Net 4.5 multipart/form-datayükleme ile nasıl kullanılacağını biliyor mu ?

İnternette örnek bulamadım.


1
Ben denedim ama nasıl başlatmak için herhangi bir fikrim yok .. nerede içeriğe byteArray eklemek vb. Başlangıç ​​yardımına ihtiyacım var.
ident

Bu gönderi yanıtına bakabilirsiniz. (Proxy ayarlarıyla) stackoverflow.com/a/50462636/2123797
Ergin Çelik

Yanıtlar:


156

benim sonucum şöyle:

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

6
Vay be, büyük dosyaları REST API'ye yüklerken bunu yapmak çok daha basit. Teşekkürler için yorum yapmak istemiyorum, ama teşekkürler. Windows Phone 8 için taşınabilir.
Léon Pelletier

1
Sınır dizesi new MultipartFormDataContent(...)geçersiz bir sınır karakteri içerdiğinden (belki "/" ayırıcısı) bu kod benim için başarısız oldu . Hata yok, sadece sunucuya hiçbir dosya gönderilmedi - benim durumumda, Context.Request.Files.Count = 0 API denetleyicisinde. Muhtemelen sadece bir Nancysorun, ama DateTime.Now.Ticks.ToString("x")bunun yerine bir şey kullanmanızı öneririm .
Dunc

7
@MauricioAviles, bağlantınız koptu. Bunu güzel açıklayan bir tane buldum: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Kevin Harker

1
Bir hata alırsanız: " Yüklenen dosya bulunamadı " keyve fileNameparametrelerini content( bu örnekte bilddatei ve upload.jpg ) eklemeyi deneyin .
jhhwilliams

1
@KevinHarker, İkinci bağlantıyı tekrar oku. HttpClient'i atmama hakkında konuşulan paragraf önceki tasarıma atıfta bulunuyordu. Kafasını karıştırmak kolaydır. Temel olarak, IHttpClientFactory ile HttpClient Dispose gerçekten hiçbir şey yapmaz ( stackoverflow.com/a/54326424/476048 ) ve dahili işleyiciler HttpClientFactory tarafından yönetilir.
Berin Loritsch

83

Aşağı yukarı böyle çalışır (bir image / jpg dosyası kullanma örneği):

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

(Ne requestContent.Add()istersen yapabilirsin , HttpContent soyuna bir göz at mevcut türlerin geçebileceğini görmek bakın)

Tamamlandığında, içinde HttpResponseMessage.Contentkullanabileceğiniz yanıt içeriğini bulacaksınız HttpContent.ReadAs*Async.


2
Ahhh // here you can specify boundary if you need---^:) için teşekkürler
sfarbota

1
neden çalışmıyor? genel zaman uyumsuz Görev <string> SendImage (bayt [] foto) {var requestContent = new MultipartFormDataContent (); var imageContent = yeni ByteArrayContent (foto); imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse ("image / jpeg"); requestContent.Add (imageContent, "foto", "foto.jpg"); string url = " myAddress / myWS / api / Home / SendImage? foto = "; acliit _client.PostAsync (url, requestContent); dönüş "tamam"; }
atapi19

1
asyncilk satırda ve awaitson satırdan önceki satırda gereksizdir.
1valdis

Büyük dosyalar için, isteğe bayt dizisi yerine akış içeriği ekleyin.
Elisabeth

1
@WDRust, bir bayt dizisi ile önce tüm dosyayı belleğe yükler ve sonra gönderirsiniz. Akış içeriğiyle, dosya bellek açısından daha verimli olan bir arabellek kullanılarak okunur ve gönderilir.
Josef Bláha

53

Bu, MultipartFormDataContent kullanarak HTTPClient ile dize ve dosya akışının nasıl gönderileceğinin bir örneğidir. Her HTTPContent için Content-Disposition ve Content-Type belirtilmelidir:

İşte benim örneğim. Umarım yardımcı olur:

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

11
@Trout Kodunuzun bugün beni nasıl mutlu ettiğini bilmiyorsunuz! +1
Tutam

6
Cevap tam olarak bu.
VK

2
Teşekkür notu yorumlamamız gerekmediğini biliyorum. Ama burada bu nasıl kullanılacağını gördüğüm en iyi kod MultipartFormDataContent. Kudos to you efendim
sebagomez

Kabul. Bu, yük içeriğinin bir parçası olarak json dizesi ve dosyasını içeren tek yanıttır.
frostshoxx

Bilgisayarımda (win7 sp1, IIS 7.5) Content-Typeve olmadan Tamam'ı test ediyorum Content-Disposition, ancak Server 2008 R2'de (IIS 7.5) dosyaları bulamıyorum, garip. Bu yüzden cevap olarak yapıyorum.
chengzi

18

A HttpClientyüklemek için nasıl kullanılacağı ile ilgili başka bir örnek multipart/form-data.

Bir dosyayı bir REST API'sine yükler ve dosyanın kendisini (örn. JPG) ve ek API parametrelerini içerir. Dosya doğrudan üzerinden yerel diskten yüklenir FileStream.

Ek API'ya özgü mantık da dahil olmak üzere tam örnek için buraya bakın .

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

12

Bu benim için çalışıyor deneyin.

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

Kusursuz. Tam olarak ne TestServer.CreatClient()bir veri + dosya yükleme için bir entegrasyon testi bir .NET Core senaryosunda aradığını .
Vedran Mandić

yöntem HTTPGET ise formcontent nasıl iletilir
MBG

@ MBG GET isteklerinin normalde kural gereği bir istek gövdesi yoktur, bu nedenle GET kullanarak dosya yükleyemezsiniz (veya gönderdiğiniz sunucu çok sıra dışı değilse - çoğu web sunucusu beklemez veya desteklemez) , çünkü dosyayı veya beraberindeki form verilerini içerecek bir istek gövdesi yoktur. Teknik olarak bunun teorik olarak yapılmasını engelleyecek hiçbir şey olmadığına inanıyorum, sadece HTTP'nin neredeyse tüm uygulamalarındaki konvansiyonun anlamsal olarak, GET'in öncelikle bilgi almak için olduğunu (göndermek yerine) ve bir gövdesinin olmadığı
ADyson

9

İşte benim için çalışan tam bir örnek. boundaryİstekte değer .NET tarafından otomatik olarak eklenir.

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;

Bununla nasıl jeton gönderebiliriz? Lütfen

@Softlion - Göndermeden önce belleğe yüklemek DEĞİL sorun yaşıyorum. Daha iyi bir yol biliyorsanız, lütfen buraya gönderin: stackoverflow.com/questions/52446969/…
emery.noel

1

Ön yükleyici Dotnet 3.0 Core ile örnek

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

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

Bu senaryo, güvenlik sertifikası ile API sitesine dosya yüklemek için kullanılır
Rajenthiran T

0

Nasıl bir dosya DELETE http fiil maruz bırakılmış bir API göndermek için gösteren bir kod pasajı ekliyorum. Bu, DELETE http fiili bir dosya yüklemek için yaygın bir durum değildir, ancak izin verilir. Aramayı yetkilendirmek için Windows NTLM kimlik doğrulamasını varsaydım.

Bir kudreti yüzü tüm aşırı yükler olduğunu çok sorun HttpClient.DeleteAsyncyöntemi için herhangi bir parametre var HttpContentbiz bunu elde arada PostAsyncyöntemiyle

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 # dosyanızın üst kısmında aşağıdaki ad alanlarına ihtiyacınız vardır:

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

PS Kodumda çok fazla blok (IDisposable pattern) kullanarak üzgünüm. Ne yazık ki, C # yapısını kullanma sözdizimi tek bir ifadede birden çok değişkenin başlatılmasını desteklemez.


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


Tamam msrd! Acemim için üzgünüm. "Erik Kalkoke" gibi açık bir kod koymaya çalışıyorum. Ben sunucu düğümü 1 IFormFile tarafından görüntü almak gibi kod paylaşacağım ve sınıf [MultipartFormDataContent] aracılığıyla bazı metni artırarak sunucu düğümü 2 geçmek. böyle son satır. sonuç = res.Content.ReadAsStringAsync ();
Jack The Ripper
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.