C # HttpClient 4.5 멀티 파트 / 양식 데이터 업로드


145

누구나 HttpClient.Net 4.5에서 multipart/form-data업로드 와 함께 사용하는 방법을 알고 있습니까?

인터넷에서 예를 찾을 수 없습니다.


1
나는 시도했지만 그것을 시작하는 방법을 전혀 모른다. 어디에서 byteArray를 내용에 추가 하는가 등. 나는 일종의 시작 도움이 필요합니다.
ident

이 게시물 답변을 볼 수 있습니다. (프록시 설정) stackoverflow.com/a/50462636/2123797
Ergin Çelik

답변:


156

내 결과는 다음과 같습니다

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
큰 파일을 REST API에 업로드 할 때이 작업을 수행하는 것이 훨씬 간단합니다. 고마워요.하지만 고마워요. Windows Phone 8 용으로 이식 가능합니다.
Léon Pelletier

1
전달 된 경계 문자열 new MultipartFormDataContent(...)에 유효하지 않은 경계 문자 ( "/"구분자) 가 포함되어 있어이 코드가 실패했습니다 . 오류가 없으며 서버에 파일이 게시되지 않았습니다. 필자의 경우 API 컨트롤러에서 Context.Request.Files.Count = 0입니다. 아마도 Nancy문제 일 수도 있지만 DateTime.Now.Ticks.ToString("x")대신 비슷한 것을 사용하는 것이 좋습니다 .
Dunc September

7
@MauricioAviles, 링크가 끊어졌습니다. : 나는 멋지게 설명이 하나 발견 aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
케빈 하커

1
오류가 나타나면 : " 업로드 된 파일을 찾을 수 없음 추가하려고" keyfileName매개 변수를 content( bilddateiupload.jpg 이 예에서).
jhhwilliams

1
@KevinHarker, 두 번째 링크를 다시 읽으십시오. HttpClient를 폐기하지 않는 것에 대한 단락은 이전 디자인을 언급했습니다. 혼동하기 쉽습니다. 기본적으로 IHttpClientFactory를 사용하면 HttpClient Dispose는 실제로 아무것도하지 않으며 ( stackoverflow.com/a/54326424/476048 ) 내부 핸들러는 HttpClientFactory에 의해 관리됩니다.
Berin Loritsch

83

다음과 같이 다소 작동합니다 (image / 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 자손 을 살펴보십시오)

완료 HttpResponseMessage.Content되면와 함께 사용할 수있는 응답 콘텐츠를 찾을 수 있습니다 HttpContent.ReadAs*Async.


2
Ahhh // here you can specify boundary if you need---^:)
sfarbota

1
왜 이것이 작동하지 않습니까? 공용 비동기 작업 <문자열> 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 = "; Await _client.PostAsync (url, requestContent); "확인"을 반환; }
atapi19

1
async첫 번째 줄과 await마지막 줄 앞의 줄은 불필요합니다.
1valdis

큰 파일의 경우 바이트 배열이 아닌 요청에 스트림 내용을 추가하십시오.
엘리자베스

1
@WDRust는 바이트 배열을 사용하여 먼저 전체 파일을 메모리에로드 한 다음 보냅니다. 스트림 컨텐츠의 경우 파일은 버퍼를 사용하여 읽고 전송되므로 메모리 측면에서 더 효율적입니다.
Josef Bláha

53

다음은 MultipartFormDataContent를 사용하여 HTTPClient로 문자열 및 파일 스트림을 게시하는 방법의 예입니다. 각 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();
        }
    }
}

11
@Trout 당신은 당신의 코드가 어떻게 오늘 나를 행복하게했는지 전혀 모른다! +1
Pinch

6
이것이 완전한 답변입니다.
VK

2
우리가 고맙다는 말을해서는 안된다는 것을 알고 있습니다. 그러나 이것은 바로 사용 방법에서 본 최고의 코드 MultipartFormDataContent입니다. 당신에게 선생님
sebagomez

동의했다. 이것은 페이로드 컨텐츠의 일부로 json 문자열과 파일을 포함하는 유일한 답변입니다.
frostshoxx

내 컴퓨터에서 나는 시험없이 (WIN7 SP1로는 7.5 IIS) Content-TypeContent-Disposition이 이상하다, 좋아하지만, 서버 2008 R2는 (7.5 IIS) 파일을 찾을 수 없습니다. 그래서 나는 대답합니다.
chengzi

18

다음 HttpClient은를 업로드 하는 데 사용하는 방법에 대한 또 다른 예입니다 multipart/form-data.

파일을 REST API에 업로드하고 파일 자체 (예 : JPG) 및 추가 API 매개 변수를 포함합니다. 파일은를 통해 로컬 디스크에서 직접 업로드됩니다 FileStream.

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

12

이것이 나를 위해 노력하십시오.

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

완벽한. TestServer.CreatClient()데이터 + 파일 업로드에 대한 통합 테스트의 .NET Core 시나리오 에서 내가 찾던 것입니다 .
Vedran Mandić

메소드가 HTTPGET 인 경우 formcontent를 전달하는 방법
MBG

@MBG GET 요청에는 일반적으로 규칙에 따라 요청 본문이 없으므로 GET을 사용하여 파일을 업로드 할 수 없습니다 (또는 보내는 서버가 매우 이례적인 경우가 아니라면 대부분의 웹 서버는이를 기대하거나 지원하지 않습니다) 파일 또는 첨부 양식 데이터를 포함 할 요청 본문이 없기 때문입니다. 나는 기술적 이론에서 수행되는 이러한 문제를 방지 할 아무것도 그 생각은 HTTP의 거의 모든 구현에서이 협약이 의미, GET은 주로 정보를 검색 (보다는 전송) 몸이없는 있도록위한 것입니다 단지입니다
에이디 슨

9

나를 위해 일한 완전한 샘플이 있습니다. 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;

우리는 이것을 어떻게 토큰을 보낼 수 있습니까? 참조하시기 바랍니다 : stackoverflow.com/questions/48295877/…

@Softlion-보내기 전에 메모리에로드하지 않는 데 문제가 있습니다. 더 좋은 방법을 알고 있다면 여기에 게시하십시오 : stackoverflow.com/questions/52446969/…
emery.noel

1

프리 로더 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();
        }
    }
}

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

이 시나리오는 보안 인증서를 사용하여 API 사이트에 파일을 업로드하는 데 사용됩니다.
Rajenthiran T

0

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;

추신 내 코드에서 블록 (IDisposable pattern)을 사용하는 것이 너무 죄송합니다. 불행히도 C #의 구문을 사용하는 구문은 단일 명령문에서 여러 변수의 초기화를 지원하지 않습니다.


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

작성한 코드에 주석을
달아서

알았어 msrd! 내 초보자에 대해 죄송합니다. "Erik Kalkoke"와 같은 명확한 코드를 넣으려고합니다. 서버 노드 1에서 IFormFile의 이미지 수신과 같은 코드를 공유하고 클래스 [MultipartFormDataContent]를 통해 일부 텍스트를 증가시켜 서버 노드 2로 전달합니다. 이 같은 마지막 줄. 결과 = 기다립니다 res.Content.ReadAsStringAsync ();
잭 리퍼
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.