2008-10-20 3 views
50

Я пытаюсь заполнить форму в php-приложении от клиента C# (Outlook addin). Я использовал Fiddler, чтобы увидеть исходный запрос из php-приложения, и форма передается как multipart/form. К сожалению .Net не имеет встроенной поддержки для этого типа форм (у WebClient есть только способ для загрузки файла). Кто-нибудь знает библиотеку или имеет какой-то код для этого? Я хочу публиковать различные значения и дополнительно (но только иногда) файл.Многостраничные формы от клиента C#

Спасибо за вашу помощь, Sebastian

+0

Это работает как шарм [www.briangrinstead.com/blog](http://www.briangrinstead.com/blog/multipart-form-post-in-c) – 2009-10-26 06:26:39

+0

Если вы не возражаете небольшая зависимость библиотеки, [Flurl] (https://github.com/tmenier/Flurl/issues/113) делает это примерно так же просто, как и получается. [Отказ от ответственности: я автор] – 2017-06-23 15:27:32

ответ

33

Это вырезать и вставить из какой-то пример кода я написал, надеюсь, он должен дать основы. Он поддерживает только данные файла и данные формы на данный момент.

public class PostData 
{ 

    private List<PostDataParam> m_Params; 

    public List<PostDataParam> Params 
    { 
     get { return m_Params; } 
     set { m_Params = value; } 
    } 

    public PostData() 
    { 
     m_Params = new List<PostDataParam>(); 

     // Add sample param 
     m_Params.Add(new PostDataParam("email", "MyEmail", PostDataParamType.Field)); 
    } 


    /// <summary> 
    /// Returns the parameters array formatted for multi-part/form data 
    /// </summary> 
    /// <returns></returns> 
    public string GetPostData() 
    { 
     // Get boundary, default is --AaB03x 
     string boundary = ConfigurationManager.AppSettings["ContentBoundary"].ToString(); 

     StringBuilder sb = new StringBuilder(); 
     foreach (PostDataParam p in m_Params) 
     { 
      sb.AppendLine(boundary); 

      if (p.Type == PostDataParamType.File) 
      { 
       sb.AppendLine(string.Format("Content-Disposition: file; name=\"{0}\"; filename=\"{1}\"", p.Name, p.FileName)); 
       sb.AppendLine("Content-Type: text/plain"); 
       sb.AppendLine(); 
       sb.AppendLine(p.Value);     
      } 
      else 
      { 
       sb.AppendLine(string.Format("Content-Disposition: form-data; name=\"{0}\"", p.Name)); 
       sb.AppendLine(); 
       sb.AppendLine(p.Value); 
      } 
     } 

     sb.AppendLine(boundary); 

     return sb.ToString();   
    } 
} 

public enum PostDataParamType 
{ 
    Field, 
    File 
} 

public class PostDataParam 
{ 


    public PostDataParam(string name, string value, PostDataParamType type) 
    { 
     Name = name; 
     Value = value; 
     Type = type; 
    } 

    public string Name; 
    public string FileName; 
    public string Value; 
    public PostDataParamType Type; 
} 

Чтобы отправить данные, которые затем необходимо:

HttpWebRequest oRequest = null; 
oRequest = (HttpWebRequest)HttpWebRequest.Create(oURL.URL); 
oRequest.ContentType = "multipart/form-data";      
oRequest.Method = "POST"; 
PostData pData = new PostData(); 

byte[] buffer = encoding.GetBytes(pData.GetPostData()); 

// Set content length of our data 
oRequest.ContentLength = buffer.Length; 

// Dump our buffered postdata to the stream, booyah 
oStream = oRequest.GetRequestStream(); 
oStream.Write(buffer, 0, buffer.Length); 
oStream.Close(); 

// get the response 
oResponse = (HttpWebResponse)oRequest.GetResponse(); 

Надежда то будет ясно, я вырезать и вставить из нескольких источников, чтобы получить, что опрятнее.

+0

Я не думаю, что это работает, граница не определена в Content-Type и должна быть добавлена ​​слева «-» границы для каждого из написанных и «-» справа от последнего. Не спрашивайте меня, как появляется эта магическая «-», они указаны в официальной документации: https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 Если вам не нравятся магические требования, как я, вам будет трудно выполнять эту работу так же, как и я. – 2016-03-31 16:16:05

+0

Этот код определенно работает для сценариев, в которых я его использовал. Однако я вижу, что, пока я определяю, что полная граница должна быть отправлена ​​в почтовые данные, я не указал, добавив это в общий заголовок содержимого в качестве разделителя границ. Что касается магического числа, это определяется клиентом, чтобы убедиться, что оно уникально и не будет отображаться внутри контента в любом месте. Подробнее см. Здесь: https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html – dnolan 2016-04-15 09:04:09

13

Строительство на dnolans Например, это версия, которую я мог бы реально получить работу (там были некоторые ошибки с границей, кодировка не была установлена) :-)

Для передачи данных:

HttpWebRequest oRequest = null; 
oRequest = (HttpWebRequest)HttpWebRequest.Create("http://you.url.here"); 
oRequest.ContentType = "multipart/form-data; boundary=" + PostData.boundary; 
oRequest.Method = "POST"; 
PostData pData = new PostData(); 
Encoding encoding = Encoding.UTF8; 
Stream oStream = null; 

/* ... set the parameters, read files, etc. IE: 
    pData.Params.Add(new PostDataParam("email", "[email protected]", PostDataParamType.Field)); 
    pData.Params.Add(new PostDataParam("fileupload", "filename.txt", "filecontents" PostDataParamType.File)); 
*/ 

byte[] buffer = encoding.GetBytes(pData.GetPostData()); 

oRequest.ContentLength = buffer.Length; 

oStream = oRequest.GetRequestStream(); 
oStream.Write(buffer, 0, buffer.Length); 
oStream.Close(); 

HttpWebResponse oResponse = (HttpWebResponse)oRequest.GetResponse(); 

класс PostData должен выглядеть следующим образом:

public class PostData 
{ 
    // Change this if you need to, not necessary 
    public static string boundary = "AaB03x"; 

    private List<PostDataParam> m_Params; 

    public List<PostDataParam> Params 
    { 
     get { return m_Params; } 
     set { m_Params = value; } 
    } 

    public PostData() 
    { 
     m_Params = new List<PostDataParam>(); 
    } 

    /// <summary> 
    /// Returns the parameters array formatted for multi-part/form data 
    /// </summary> 
    /// <returns></returns> 
    public string GetPostData() 
    { 
     StringBuilder sb = new StringBuilder(); 
     foreach (PostDataParam p in m_Params) 
     { 
      sb.AppendLine("--" + boundary); 

      if (p.Type == PostDataParamType.File) 
      { 
       sb.AppendLine(string.Format("Content-Disposition: file; name=\"{0}\"; filename=\"{1}\"", p.Name, p.FileName)); 
       sb.AppendLine("Content-Type: application/octet-stream"); 
       sb.AppendLine(); 
       sb.AppendLine(p.Value); 
      } 
      else 
      { 
       sb.AppendLine(string.Format("Content-Disposition: form-data; name=\"{0}\"", p.Name)); 
       sb.AppendLine(); 
       sb.AppendLine(p.Value); 
      } 
     } 

     sb.AppendLine("--" + boundary + "--"); 

     return sb.ToString(); 
    } 
} 

public enum PostDataParamType 
{ 
    Field, 
    File 
} 

public class PostDataParam 
{ 
    public PostDataParam(string name, string value, PostDataParamType type) 
    { 
     Name = name; 
     Value = value; 
     Type = type; 
    } 

    public PostDataParam(string name, string filename, string value, PostDataParamType type) 
    { 
     Name = name; 
     Value = value; 
     FileName = filename; 
     Type = type; 
    } 

    public string Name; 
    public string FileName; 
    public string Value; 
    public PostDataParamType Type; 
} 
+0

Это решение отлично работало для меня. Спасибо! – Steve 2017-06-15 11:24:22

0

мне нужно, чтобы имитировать вход браузера на веб-сайт, чтобы получить логин печенье, и форма Войти был многокомпонентные/форм-данных.

Я взял некоторые подсказки из других ответов здесь, а затем попытался заставить мой собственный сценарий работать. Потребовалось немного расстраивает проб и ошибок, прежде чем он работал правильно, но вот код:

public static class WebHelpers 
    { 
     /// <summary> 
     /// Post the data as a multipart form 
     /// </summary> 
     public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, Dictionary<string, string> values) 
     { 
      string formDataBoundary = "---------------------------" + WebHelpers.RandomHexDigits(12); 
      string contentType = "multipart/form-data; boundary=" + formDataBoundary; 

      string formData = WebHelpers.MakeMultipartForm(values, formDataBoundary); 
      return WebHelpers.PostForm(postUrl, userAgent, contentType, formData); 
     } 

     /// <summary> 
     /// Post a form 
     /// </summary> 
     public static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, string formData) 
     { 
      HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest; 

      if (request == null) 
      { 
       throw new NullReferenceException("request is not a http request"); 
      } 

      // Add these, as we're doing a POST 
      request.Method = "POST"; 
      request.ContentType = contentType; 
      request.UserAgent = userAgent; 
      request.CookieContainer = new CookieContainer(); 

      // We need to count how many bytes we're sending. 
      byte[] postBytes = Encoding.UTF8.GetBytes(formData); 
      request.ContentLength = postBytes.Length; 

      using (Stream requestStream = request.GetRequestStream()) 
      { 
       // Push it out there 
       requestStream.Write(postBytes, 0, postBytes.Length); 
       requestStream.Close(); 
      } 

      return request.GetResponse() as HttpWebResponse; 
     } 

     /// <summary> 
     /// Generate random hex digits 
     /// </summary> 
     public static string RandomHexDigits(int count) 
     { 
      Random random = new Random(); 
      StringBuilder result = new StringBuilder(); 
      for (int i = 0; i < count; i++) 
      { 
       int digit = random.Next(16); 
       result.AppendFormat("{0:x}", digit); 
      } 

      return result.ToString(); 
     } 

     /// <summary> 
     /// Turn the key and value pairs into a multipart form 
     /// </summary> 
     private static string MakeMultipartForm(Dictionary<string, string> values, string boundary) 
     { 
      StringBuilder sb = new StringBuilder(); 

      foreach (var pair in values) 
      { 
       sb.AppendFormat("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n", boundary, pair.Key, pair.Value); 
      } 

      sb.AppendFormat("--{0}--\r\n", boundary); 

      return sb.ToString();  
     } 
    } 
} 

Он не обрабатывает данные файла, просто сформировать так, что все, что мне было нужно. Я так называл:

try 
    { 
     using (HttpWebResponse response = WebHelpers.MultipartFormDataPost(postUrl, UserAgentString, this.loginForm)) 
     { 
      if (response != null) 
      { 
       Cookie loginCookie = response.Cookies["logincookie"]; 
       ..... 
68

Спасибо за ответы, всем! Я недавно должен был заставить это работать, и сильно использовал ваши предложения. Однако было несколько сложных частей, которые не работали так, как ожидалось, в основном связанные с фактическим включением файла (что было важной частью вопроса). Здесь уже много ответов, но я думаю, что это может быть полезно кому-то в будущем (я не смог найти много четких примеров этого онлайн). I wrote a blog post, что объясняет это немного больше.

В основном, я сначала попытался передать данные файла как кодированную строку UTF8, но у меня были проблемы с файлами кодирования (он отлично работал для обычного текстового файла, но при загрузке Word Document, например, если Я попытался сохранить файл, который был передан в опубликованную форму, используя Request.Files [0] .SaveAs(), открытие файла в Word не получилось. Я обнаружил, что если вы пишете данные файла напрямую с помощью Stream (а не StringBuilder), он работал, как и ожидалось. Кроме того, я сделал несколько изменений, которые сделали это проще для меня понять.

к слову, Multipart Forms Request for Comments и W3C Recommendation for mulitpart/form-data пара полезных ресурсов в случае, если кто требуется ссылка для спецификации.

Я изменил класс WebHelpers, чтобы быть немного меньшим и иметь более простые интерфейсы, теперь он называется FormUpload. Если вы пройдете FormUpload.FileParameter, вы можете передать содержимое байта [] вместе с именем файла и типом контента, и если вы передадите строку, он будет рассматривать его как стандартную комбинацию имен/значений.

Вот класс FormUpload:

// Implements multipart/form-data POST in C# http://www.ietf.org/rfc/rfc2388.txt 
// http://www.briangrinstead.com/blog/multipart-form-post-in-c 
public static class FormUpload 
{ 
    private static readonly Encoding encoding = Encoding.UTF8; 
    public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, Dictionary<string, object> postParameters) 
    { 
     string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid()); 
     string contentType = "multipart/form-data; boundary=" + formDataBoundary; 

     byte[] formData = GetMultipartFormData(postParameters, formDataBoundary); 

     return PostForm(postUrl, userAgent, contentType, formData); 
    } 
    private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData) 
    { 
     HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest; 

     if (request == null) 
     { 
      throw new NullReferenceException("request is not a http request"); 
     } 

     // Set up the request properties. 
     request.Method = "POST"; 
     request.ContentType = contentType; 
     request.UserAgent = userAgent; 
     request.CookieContainer = new CookieContainer(); 
     request.ContentLength = formData.Length; 

     // You could add authentication here as well if needed: 
     // request.PreAuthenticate = true; 
     // request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested; 
     // request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes("username" + ":" + "password"))); 

     // Send the form data to the request. 
     using (Stream requestStream = request.GetRequestStream()) 
     { 
      requestStream.Write(formData, 0, formData.Length); 
      requestStream.Close(); 
     } 

     return request.GetResponse() as HttpWebResponse; 
    } 

    private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary) 
    { 
     Stream formDataStream = new System.IO.MemoryStream(); 
     bool needsCLRF = false; 

     foreach (var param in postParameters) 
     { 
      // Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added. 
      // Skip it on the first parameter, add it to subsequent parameters. 
      if (needsCLRF) 
       formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n")); 

      needsCLRF = true; 

      if (param.Value is FileParameter) 
      { 
       FileParameter fileToUpload = (FileParameter)param.Value; 

       // Add just the first part of this param, since we will write the file data directly to the Stream 
       string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n", 
        boundary, 
        param.Key, 
        fileToUpload.FileName ?? param.Key, 
        fileToUpload.ContentType ?? "application/octet-stream"); 

       formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header)); 

       // Write the file data directly to the Stream, rather than serializing it to a string. 
       formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length); 
      } 
      else 
      { 
       string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", 
        boundary, 
        param.Key, 
        param.Value); 
       formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData)); 
      } 
     } 

     // Add the end of the request. Start with a newline 
     string footer = "\r\n--" + boundary + "--\r\n"; 
     formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer)); 

     // Dump the Stream into a byte[] 
     formDataStream.Position = 0; 
     byte[] formData = new byte[formDataStream.Length]; 
     formDataStream.Read(formData, 0, formData.Length); 
     formDataStream.Close(); 

     return formData; 
    } 

    public class FileParameter 
    { 
     public byte[] File { get; set; } 
     public string FileName { get; set; } 
     public string ContentType { get; set; } 
     public FileParameter(byte[] file) : this(file, null) { } 
     public FileParameter(byte[] file, string filename) : this(file, filename, null) { } 
     public FileParameter(byte[] file, string filename, string contenttype) 
     { 
      File = file; 
      FileName = filename; 
      ContentType = contenttype; 
     } 
    } 
} 

Вот код вызова, который загружает файл и несколько нормальных параметров пост:

// Read file data 
FileStream fs = new FileStream("c:\\people.doc", FileMode.Open, FileAccess.Read); 
byte[] data = new byte[fs.Length]; 
fs.Read(data, 0, data.Length); 
fs.Close(); 

// Generate post objects 
Dictionary<string, object> postParameters = new Dictionary<string, object>(); 
postParameters.Add("filename", "People.doc"); 
postParameters.Add("fileformat", "doc"); 
postParameters.Add("file", new FormUpload.FileParameter(data, "People.doc", "application/msword")); 

// Create request and receive response 
string postURL = "http://localhost"; 
string userAgent = "Someone"; 
HttpWebResponse webResponse = FormUpload.MultipartFormDataPost(postURL, userAgent, postParameters); 

// Process response 
StreamReader responseReader = new StreamReader(webResponse.GetResponseStream()); 
string fullResponse = responseReader.ReadToEnd(); 
webResponse.Close(); 
Response.Write(fullResponse); 
+7

чувак, ты чемпион! – andy 2009-12-10 05:47:24

+0

Удивительный код. Спасибо. – 2010-08-04 18:36:27

0

Ниже приведен код, который Я пользуюсь

//This URL not exist, it's only an example. 
    string url = "http://myBox.s3.amazonaws.com/"; 
    //Instantiate new CustomWebRequest class 
    CustomWebRequest wr = new CustomWebRequest(url); 
    //Set values for parameters 
    wr.ParamsCollection.Add(new ParamsStruct("key", "${filename}")); 
    wr.ParamsCollection.Add(new ParamsStruct("acl", "public-read")); 
    wr.ParamsCollection.Add(new ParamsStruct("success_action_redirect", "http://www.yahoo.com")); 
    wr.ParamsCollection.Add(new ParamsStruct("x-amz-meta-uuid", "14365123651274")); 
    wr.ParamsCollection.Add(new ParamsStruct("x-amz-meta-tag", "")); 
    wr.ParamsCollection.Add(new ParamsStruct("AWSAccessKeyId", "zzzz"));    
    wr.ParamsCollection.Add(new ParamsStruct("Policy", "adsfadsf")); 
    wr.ParamsCollection.Add(new ParamsStruct("Signature", "hH6lK6cA=")); 
    //For file type, send the inputstream of selected file 
    StreamReader sr = new StreamReader(@"file.txt"); 
    wr.ParamsCollection.Add(new ParamsStruct("file", sr, ParamsStruct.ParamType.File, "file.txt")); 

    wr.PostData(); 

по следующей ссылке я скачал тот же код http://www.codeproject.com/KB/cs/multipart_request_C_.aspx

Любая помощь

9

В версии .NET Я использую вас также должны сделать это:

Если вы do not, класс HttpWebRequest автоматически добавит заголовок запроса Expect:100-continue, который замалчивает все.

Также я усвоил, что у вас есть необходимое количество тире. все, что вы говорите, это «граница» в заголовке Content-Type должен предшествовать два тире

--THEBOUNDARY 

и в конце

--THEBOUNDARY-- 

точно так, как это делает в примере кода. Если на вашей границе много дефисов, за которыми следует номер, эта ошибка не будет очевидна, если посмотреть на http-запрос в прокси-сервере

2

Небольшая оптимизация класса раньше. В этой версии файлы не полностью загружены в память.

Совет по безопасности: проверка границы отсутствует, если файл содержит ограничение, он будет аварийно завершен.

namespace WindowsFormsApplication1 
{ 
    public static class FormUpload 
    { 
     private static string NewDataBoundary() 
     { 
      Random rnd = new Random(); 
      string formDataBoundary = ""; 
      while (formDataBoundary.Length < 15) 
      { 
       formDataBoundary = formDataBoundary + rnd.Next(); 
      } 
      formDataBoundary = formDataBoundary.Substring(0, 15); 
      formDataBoundary = "-----------------------------" + formDataBoundary; 
      return formDataBoundary; 
     } 

     public static HttpWebResponse MultipartFormDataPost(string postUrl, IEnumerable<Cookie> cookies, Dictionary<string, string> postParameters) 
     { 
      string boundary = NewDataBoundary(); 

      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl); 

      // Set up the request properties 
      request.Method = "POST"; 
      request.ContentType = "multipart/form-data; boundary=" + boundary; 
      request.UserAgent = "PhasDocAgent 1.0"; 
      request.CookieContainer = new CookieContainer(); 

      foreach (var cookie in cookies) 
      { 
       request.CookieContainer.Add(cookie); 
      } 

      #region WRITING STREAM 
      using (Stream formDataStream = request.GetRequestStream()) 
      { 
       foreach (var param in postParameters) 
       { 
        if (param.Value.StartsWith("file://")) 
        { 
         string filepath = param.Value.Substring(7); 

         // Add just the first part of this param, since we will write the file data directly to the Stream 
         string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n", 
          boundary, 
          param.Key, 
          Path.GetFileName(filepath) ?? param.Key, 
          MimeTypes.GetMime(filepath)); 

         formDataStream.Write(Encoding.UTF8.GetBytes(header), 0, header.Length); 

         // Write the file data directly to the Stream, rather than serializing it to a string. 

         byte[] buffer = new byte[2048]; 

         FileStream fs = new FileStream(filepath, FileMode.Open); 

         for (int i = 0; i < fs.Length;) 
         { 
          int k = fs.Read(buffer, 0, buffer.Length); 
          if (k > 0) 
          { 
           formDataStream.Write(buffer, 0, k); 
          } 
          i = i + k; 
         } 
         fs.Close(); 
        } 
        else 
        { 
         string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n", 
          boundary, 
          param.Key, 
          param.Value); 
         formDataStream.Write(Encoding.UTF8.GetBytes(postData), 0, postData.Length); 
        } 
       } 
       // Add the end of the request 
       byte[] footer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n"); 
       formDataStream.Write(footer, 0, footer.Length); 
       request.ContentLength = formDataStream.Length; 
       formDataStream.Close(); 
      } 
      #endregion 

      return request.GetResponse() as HttpWebResponse; 
     } 
    } 
} 
3

Спасибо за код, это сэкономило мне много времени (включая ошибку Except100!).

Во всяком случае, я нашел ошибку в коде, здесь:

formDataStream.Write(encoding.GetBytes(postData), 0, postData.Length); 

В случае, если данные POST является UTF-16, postData.Length, возвращает количество символов, а не число байтов. Это усечет публикуемые данные (например, если у вас есть 2 символа, которые кодируются как utf-16, они берут 4 байта, но postData.Length скажет, что он занимает 2 байта, и вы теряете два последних байта опубликованных данные).

Решение - заменить эту строку с:

byte[] aPostData=encoding.GetBytes(postData); 
formDataStream.Write(aPostData, 0, aPostData.Length); 

Используя это, длина вычисляется по размеру байт [], а не размер строки.

0

Моя реализация

/// <summary> 
/// Sending file via multipart\form-data 
/// </summary> 
/// <param name="url">URL for send</param> 
/// <param name="file">Local file path</param> 
/// <param name="paramName">Request file param</param> 
/// <param name="contentType">Content-Type file headr</param> 
/// <param name="nvc">Additional post params</param> 
private static string httpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc) 
{ 
    //delimeter 
    var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); 

    //creating request 
    var wr = (HttpWebRequest)WebRequest.Create(url); 
    wr.ContentType = "multipart/form-data; boundary=" + boundary; 
    wr.Method = "POST"; 
    wr.KeepAlive = true; 

    //sending request 
    using(var requestStream = wr.GetRequestStream()) 
    { 
     using (var requestWriter = new StreamWriter(requestStream, Encoding.UTF8)) 
     { 
      //params 
      const string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}"; 
      foreach (string key in nvc.Keys) 
      { 
       requestWriter.Write(boundary); 
       requestWriter.Write(String.Format(formdataTemplate, key, nvc[key])); 
      } 
      requestWriter.Write(boundary); 

      //file header 
      const string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n"; 
      requestWriter.Write(String.Format(headerTemplate, paramName, file, contentType)); 

      //file content 
      using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read)) 
      { 
       fileStream.CopyTo(requestStream); 
      } 

      requestWriter.Write("\r\n--" + boundary + "--\r\n"); 
     } 
    } 

    //reading response 
    try 
    { 
     using (var wresp = (HttpWebResponse)wr.GetResponse()) 
     { 
      if (wresp.StatusCode == HttpStatusCode.OK) 
      { 
       using (var responseStream = wresp.GetResponseStream()) 
       { 
        if (responseStream == null) 
         return null; 
        using (var responseReader = new StreamReader(responseStream)) 
        { 
         return responseReader.ReadToEnd(); 
        } 
       } 
      } 

      throw new ApplicationException("Error while upload files. Server status code: " + wresp.StatusCode.ToString()); 
     } 
    } 
    catch (Exception ex) 
    { 
     throw new ApplicationException("Error while uploading file", ex); 
    } 
} 
26

С .NET 4.5 вы в настоящее время можно использовать System.Net.Http пространство имен. Ниже приведен пример загрузки одного файла с использованием данных многостраничной формы.

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

namespace HttpClientTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var client = new HttpClient(); 
      var content = new MultipartFormDataContent(); 
      content.Add(new StreamContent(File.Open("../../Image1.png", FileMode.Open)), "Image", "Image.png"); 
      content.Add(new StringContent("Place string content here"), "Content-Id in the HTTP"); 
      var result = client.PostAsync("https://hostname/api/Account/UploadAvatar", content); 
      Console.WriteLine(result.Result.ToString()); 
     } 
    } 
} 
Смежные вопросы