【问题标题】:Multipart forms from C# client来自 C# 客户端的多部分表单
【发布时间】:2010-09-18 04:52:06
【问题描述】:

我正在尝试从 C# 客户端(Outlook 插件)在 php 应用程序中填写表单。我使用 Fiddler 从 php 应用程序中查看原始请求,并且表单作为 multipart/form 传输。不幸的是,.Net 并没有对这种类型的表单提供原生支持(WebClient 只有一种上传文件的方法)。 有人知道图书馆或有一些代码来实现这一点吗?我想发布不同的值和另外(但只是有时)一个文件。

感谢您的帮助, 塞巴斯蒂安

【问题讨论】:

标签: c# http multipartform-data


【解决方案1】:

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

【讨论】:

  • 如果我在 URL 中获取多部分表单的详细信息,这里询问的是 pdf 等文件
  • 您可以使用 content.Add(new StringContent("1"),"MyId"); 添加更多表单数据内容(如 Id)
【解决方案2】:

我的实现

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

【讨论】:

    【解决方案3】:

    对之前的类做了一点优化。 在这个版本中,文件并没有完全加载到内存中。

    安全建议:缺少边界检查,如果文件包含边界,它将崩溃。

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

    【讨论】:

      【解决方案4】:

      谢谢大家的回答!我最近不得不让这个工作,并大量使用你的建议。但是,有几个棘手的部分没有按预期工作,主要与实际包含文件有关(这是问题的重要部分)。这里已经有很多答案,但我认为这可能对将来的某人有用(我在网上找不到很多明确的例子)。我wrote a blog post 解释了一点。

      基本上,我首先尝试将文件数据作为 UTF8 编码字符串传递,但我在编码文件时遇到了问题(对于纯文本文件它工作得很好,但是在上传 Word 文档时,例如,如果我尝试使用 Request.Files[0].SaveAs() 保存传递到发布表单的文件,在 Word 中打开文件无法正常工作。我发现如果您直接使用 Stream 写入文件数据(而不是比 StringBuilder),它按预期工作。另外,我做了一些修改,使我更容易理解。

      顺便说一下,Multipart Forms Request for Comments 和 W3C Recommendation for mulitpart/form-data 是一些有用的资源,以防有人需要参考规范。

      我将 WebHelpers 类更改为更小一点,并拥有更简单的接口,现在它被称为FormUpload。如果您传递FormUpload.FileParameter,您可以传递 byte[] 内容以及文件名和内容类型,如果您传递一个字符串,它会将其视为标准名称/值组合。

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

      这里是调用代码,上传一个文件和几个普通的post参数:

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

      【讨论】:

      • 壮观。我进行了修改以显示进度、支持 PUT 请求并使用我自己的 cookiecontainer,但这对我上路很有帮助。
      • 优秀的基线。我做了一些小的调整以满足我们的需求,但绝对是多部分边界发布的巨大帮助。大大简化了我的工作。谢谢
      • #Brian 我完全按照你的代码,但它不工作:(
      • 所以文件在发送前先读到内存中,如果是大文件怎么办
      【解决方案5】:

      下面是我正在使用的代码

          //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

      任何帮助

      【讨论】:

        【解决方案6】:

        感谢代码,它为我节省了很多时间(包括 except100 错误!)。

        无论如何,我在代码中发现了一个错误,在这里:

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

        如果您的 POST 数据是 utf-16,postData.Length 将返回字符数而不是字节数。这将截断正在发布的数据(例如,如果您有 2 个编码为 utf-16 的字符,它们占用 4 个字节,但 postData.Length 会说它占用 2 个字节,并且您丢失了已发布的 2 个最终字节数据)。

        解决方案 - 将该行替换为:

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

        使用这个,长度是根据字节[]的大小来计算的,而不是字符串的大小。

        【讨论】:

        • 如果您只需要确定字节数,encoding.GetByteCount(postData) 可能是更好的选择
        【解决方案7】:

        在我使用的 .NET 版本中,您也必须这样做:

        System.Net.ServicePointManager.Expect100Continue = false;
        

        如果不这样做,HttpWebRequest 类将自动添加 Expect:100-continue 请求标头,这会搞砸一切。

        我也学到了必须有正确数量的破折号的艰难方法。无论您说的是Content-Type 标头中的“边界”,都必须以两个破折号开头

        --THEBOUNDARY
        

        最后

        --THEBOUNDARY--
        

        与示例代码中的完全相同。如果您的边界是很多破折号后跟一个数字,那么通过查看代理服务器中的 http 请求,这个错误不会很明显

        【讨论】:

        • 这很重要!非常感谢您提及这一点,否则我永远不会考虑它,这是唯一让我感到困惑的事情!
        【解决方案8】:

        我需要模拟一个浏览器登录到一个网站来获取登录cookie,登录表单是multipart/form-data。

        我从这里的其他答案中获取了一些线索,然后尝试让我自己的场景发挥作用。在它正常工作之前经历了一些令人沮丧的试验和错误,但这里是代码:

            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"];
                        .....
        

        【讨论】:

          【解决方案9】:

          以 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", "example@example.com", 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;
          }
          

          【讨论】:

            【解决方案10】:

            这是从我编写的一些示例代码中剪切和粘贴的,希望它可以提供基础知识。目前只支持File数据和form-data。

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

            希望这很清楚,我已经从几个来源剪切和粘贴以使其更整洁。

            【讨论】:

            • 我不认为这行得通,边界没有在 Content-Type 中定义,并且必须在每个写入的边界的左侧添加“--”和“- -”在最后一个的右侧。不要问我这个神奇的“--”是怎么出现的,官方文档中隐含了它们:w3.org/TR/html401/interact/forms.html#h-17.13.4.2如果你不喜欢像我这样神奇的要求,你会很难像我一样完成这项工作.
            • 这段代码绝对适用于我使用过的场景。但是我看到,虽然我定义了要在发布数据中发送的完整边界,但我没有指定将其添加到整体内容中标头作为边界分隔符。至于幻数,这是由客户端确定的,以确保它是唯一的,不会出现在任何地方的内容中,更多详细信息请参见此处:w3.org/Protocols/rfc1341/7_2_Multipart.html
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-07-10
            • 2013-02-14
            相关资源
            最近更新 更多