Tải lên nhiều dữ liệu / biểu mẫu dữ liệu C # httpClient 4.5


145

Có ai biết cách sử dụng HttpClienttrong .Net 4.5 với multipart/form-datatải lên không?

Tôi không thể tìm thấy bất kỳ ví dụ trên internet.


1
Tôi đã thử nhưng tôi không biết làm thế nào để bắt đầu nó .. nơi tôi thêm byteArray vào nội dung, v.v. Tôi cần một sự giúp đỡ bắt đầu.
ident

Bạn có thể xem bài trả lời này. (Với cài đặt Proxy) stackoverflow.com/a/50462636/2123797
Ergin elik

Câu trả lời:


156

kết quả của tôi trông như thế này:

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
Ồ, thật đơn giản để làm điều này khi tải các tệp lớn lên API REST. Tôi không muốn bình luận cho cảm ơn, nhưng cảm ơn. Nó có thể mang theo cho Windows Phone 8.
Léon Pelletier

1
Mã này không thành công đối với tôi khi chuỗi ranh giới được chuyển qua new MultipartFormDataContent(...)có chứa một ký tự ranh giới không hợp lệ (có thể là dấu phân cách "/"). Không có lỗi, chỉ là không có tệp nào được đăng lên máy chủ - trong trường hợp của tôi, Context.Request.Files.Count = 0 trong bộ điều khiển API. Có thể chỉ là một Nancyvấn đề, nhưng tôi đề nghị sử dụng một cái gì đó như DateTime.Now.Ticks.ToString("x")thay thế.
Dunc

7
@MaurermoAviles, liên kết của bạn bị hỏng. Tôi đã tìm thấy cái này giải thích nó một cách độc đáo: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Kevin Harker

1
Nếu bạn gặp lỗi: " Không tìm thấy tệp đã tải lên ", hãy thử thêm keyfileNamecác tham số vào content( bilddateiupload.jpg trong ví dụ này).
jhhwilliams

1
@KevinHarker, Đọc lại liên kết thứ hai. Đoạn nói về việc không xử lý HttpClient đã đề cập đến thiết kế trước đó. Thật dễ nhầm lẫn. Về cơ bản, với IHttpClientFactory, HTTPClient Dispose không thực sự làm được gì ( stackoverflow.com/a/54326424/476048 ) và các trình xử lý nội bộ được quản lý bởi HttpClientFactory.
Berin Loritsch

83

Nó hoạt động ít nhiều như thế này (ví dụ sử dụng tệp hình ảnh / 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);
}

(Bạn có thể làm requestContent.Add()bất cứ điều gì bạn muốn, hãy xem hậu duệ của HTTPContent để xem các loại có sẵn để truyền vào)

Khi hoàn thành, bạn sẽ tìm thấy nội dung phản hồi bên trong HttpResponseMessage.Contentmà bạn có thể sử dụng HttpContent.ReadAs*Async.


2
Ahhh cảm ơn vì // here you can specify boundary if you need---^:)
sfarbota

1
Tại sao điều này không hoạt động? Nhiệm vụ async công khai <chuỗi> SendImage (byte [] foto) {var requestContent = new MultipartFormDataContent (); var imageContent = new ByteArrayContent (foto); imageContent.Headers.ContentType = MediaTypeHeaderValue.Pude ("image / jpeg"); requestContent.Add (imageContent, "foto", "foto.jpg"); chuỗi url = " myAddress / myWS / api / Home / SendImage? foto = "; đang chờ _client.PostAsync (url, requestContent); trả lại "ok"; }
atapi19

1
asynctrên dòng đầu tiên và awaittrên dòng trước cuối cùng là không cần thiết.
1valdis

Đối với các tệp lớn, thêm nội dung luồng vào yêu cầu thay vì mảng byte.
Elisabeth

1
@WDRust, với một mảng byte, trước tiên bạn tải toàn bộ tệp vào bộ nhớ và sau đó gửi nó. Với nội dung truyền phát, tệp được đọc và gửi bằng bộ đệm, hiệu quả hơn về mặt bộ nhớ.
Josef Bláha

53

Đây là một ví dụ về cách đăng chuỗi và luồng tệp bằng HTTPClient bằng MultipartFormDataContent. Bố trí nội dung và loại nội dung cần được chỉ định cho từng HTTPContent:

Đây là ví dụ của tôi. Hy vọng nó giúp:

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 Bạn không biết làm thế nào mã của bạn làm cho tôi rất vui ngày hôm nay! +1
Pinch

6
Đây là câu trả lời đầy đủ.
VK

2
Tôi biết chúng ta không nên bình luận một lời cảm ơn. Nhưng đây là mã tốt nhất tôi từng thấy về cách sử dụng MultipartFormDataContent. Kudos cho bạn thưa ngài
sebagomez

Đã đồng ý. Đây là câu trả lời duy nhất bao gồm chuỗi json và tệp như một phần của nội dung tải trọng.
frostshoxx

Tôi kiểm tra trên máy tính của mình (win7 sp1, IIS 7.5) mà không có Content-TypeContent-Dispositionvẫn ổn, nhưng trên Server 2008 R2 (IIS 7.5) không thể tìm thấy tệp, điều đó thật lạ. Vì vậy, tôi làm như câu trả lời.
chengzi

18

Đây là một ví dụ khác về cách sử dụng HttpClientđể tải lên a multipart/form-data.

Nó tải tệp lên API REST và bao gồm chính tệp đó (ví dụ: JPG) và các tham số API bổ sung. Các tập tin được tải lên trực tiếp từ đĩa cục bộ thông qua FileStream.

Xem ở đây để biết ví dụ đầy đủ bao gồm logic cụ thể API bổ sung.

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

Hãy thử nó làm việc cho tôi.

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

Hoàn mỹ. Chính xác những gì tôi đang tìm kiếm trong một TestServer.CreatClient()kịch bản .NET Core của một bài kiểm tra tích hợp để tải lên dữ liệu + tệp.
Vedran Mandić

Nếu phương thức là HTTPGET, làm thế nào để vượt qua formcontent
MBG

@MBG Các yêu cầu GET thường không có cơ quan yêu cầu theo quy ước, vì vậy bạn không thể tải lên tệp bằng GET (hoặc không trừ khi máy chủ bạn gửi đến rất bất thường - hầu hết các máy chủ web sẽ không mong đợi hoặc hỗ trợ nó) , bởi vì không có cơ quan yêu cầu bao gồm tệp hoặc dữ liệu biểu mẫu kèm theo. Tôi tin rằng về mặt kỹ thuật, không có gì ngăn cản việc này được thực hiện trên lý thuyết, chỉ là quy ước trên hầu hết tất cả các triển khai HTTP là về mặt ngữ nghĩa, GET chủ yếu để lấy thông tin (thay vì gửi) và do đó không có phần thân
ADyson

9

Đây là một mẫu hoàn chỉnh làm việc cho tôi. Các boundarygiá trị trong yêu cầu được thêm tự động bởi .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;

Làm thế nào chúng ta có thể gửi mã thông báo với điều này? Vui lòng xem phần này: stackoverflow.com/questions/48295877/ từ

@Softlion - Tôi gặp sự cố KHÔNG tải nó vào bộ nhớ trước khi gửi. Nếu bạn biết một cách tốt hơn, xin vui lòng gửi ở đây: stackoverflow.com/questions/52446969/iêu
emery.noel

1

Ví dụ với lõi tải trước Dotnet 3.0

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

Kịch bản này được sử dụng để tải tệp lên trang web API có chứng chỉ bảo mật
Rajenthiran T

0

Tôi đang thêm một đoạn mã cho biết cách đăng một tệp lên API đã được phơi bày qua động từ XÓA http. Đây không phải là trường hợp phổ biến để tải lên một tệp với động từ XÓA http nhưng nó được cho phép. Tôi đã giả sử xác thực Windows NTLM để ủy quyền cuộc gọi.

Vấn đề mà người ta có thể gặp phải là tất cả sự quá tải của HttpClient.DeleteAsyncphương thức không có tham số nào cho HttpContentcách chúng ta có được PostAsyncphương thức

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

Bạn cần các không gian tên bên dưới ở đầu tệp C # của bạn:

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

PS Xin lỗi về rất nhiều khối sử dụng (mẫu IDis Dùng) trong mã của tôi. Thật không may, cú pháp sử dụng cấu trúc của C # không hỗ trợ khởi tạo nhiều biến trong một câu lệnh.


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

Bạn có thể cải thiện câu trả lời của mình bằng cách nhận xét về mã mà bạn đã viết
msrd0

Được rồi Xin lỗi về người mới của tôi. Tôi cố gắng đặt một mã rõ ràng như "Erik Kalkoke", tôi thích nó. Tôi sẽ chia sẻ mã của mình như nhận hình ảnh bằng IFormFile tại nút máy chủ 1 và chuyển đến nút máy chủ 2 bằng cách tăng một số văn bản qua lớp [MultipartFormDataContent] Oh! dòng cuối cùng như thế này. result = đang chờ res.Content.ReadAsStringAsync ();
Jack The Ripper
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.