zoukankan      html  css  js  c++  java
  • Multipart forms from C# client

    publicclassPostData{privateList<PostDataParam> m_Params;publicList<PostDataParam>Params{
        	get {return m_Params;}set{ m_Params = value;}}publicPostData(){
        	m_Params =newList<PostDataParam>();// Add sample param
        	m_Params.Add(newPostDataParam("email","MyEmail",PostDataParamType.Field));}/// <summary>/// Returns the parameters array formatted for multi-part/form data/// </summary>/// <returns></returns>publicstringGetPostData(){// Get boundary, default is --AaB03xstring boundary =ConfigurationManager.AppSettings["ContentBoundary"].ToString();StringBuilder sb =newStringBuilder();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();}}publicenumPostDataParamType{Field,File}publicclassPostDataParam{publicPostDataParam(string name,string value,PostDataParamType type){Name= name;Value= value;Type= type;}publicstringName;publicstringFileName;publicstringValue;publicPostDataParamTypeType;}

    To send the data you then need to:

    HttpWebRequest oRequest =null;
    oRequest =(HttpWebRequest)HttpWebRequest.Create(oURL.URL);
    oRequest.ContentType="multipart/form-data";   					
    oRequest.Method="POST";PostData pData =newPostData();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();
    Here is the FormUpload class:
    // Implements multipart/form-data POST in C# http://www.ietf.org/rfc/rfc2388.txt// http://www.briangrinstead.com/blog/multipart-form-post-in-cpublicstaticclassFormUpload{privatestaticreadonlyEncoding encoding =Encoding.UTF8;publicstaticHttpWebResponseMultipartFormDataPost(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);returnPostForm(postUrl, userAgent, contentType, formData);}privatestaticHttpWebResponsePostForm(string postUrl,string userAgent,string contentType,byte[] formData){HttpWebRequest request =WebRequest.Create(postUrl)asHttpWebRequest;if(request ==null){thrownewNullReferenceException("request is not a http request");}// Set up the request properties.
            request.Method="POST";
            request.ContentType= contentType;
            request.UserAgent= userAgent;
            request.CookieContainer=newCookieContainer();
            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()asHttpWebResponse;}privatestaticbyte[]GetMultipartFormData(Dictionary<string,object> postParameters,string boundary){Stream formDataStream =newSystem.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.ValueisFileParameter){FileParameter fileToUpload =(FileParameter)param.Value;// Add just the first part of this param, since we will write the file data directly to the Streamstring 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 newlinestring 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 =newbyte[formDataStream.Length];
            formDataStream.Read(formData,0, formData.Length);
            formDataStream.Close();return formData;}publicclassFileParameter{publicbyte[]File{ get;set;}publicstringFileName{ get;set;}publicstringContentType{ get;set;}publicFileParameter(byte[] file):this(file,null){}publicFileParameter(byte[] file,string filename):this(file, filename,null){}publicFileParameter(byte[] file,string filename,string contenttype){File= file;FileName= filename;ContentType= contenttype;}}}

    Here is the calling code, which uploads a file and a few normal post parameters:

    // Read file dataFileStream fs =newFileStream("c:\\people.doc",FileMode.Open,FileAccess.Read);byte[] data =newbyte[fs.Length];
    fs.Read(data,0, data.Length);
    fs.Close();// Generate post objectsDictionary<string,object> postParameters =newDictionary<string,object>();
    postParameters.Add("filename","People.doc");
    postParameters.Add("fileformat","doc");
    postParameters.Add("file",newFormUpload.FileParameter(data,"People.doc","application/msword"));// Create request and receive responsestring postURL ="http://localhost";string userAgent ="Someone";HttpWebResponse webResponse =FormUpload.MultipartFormDataPost(postURL, userAgent, postParameters);// Process responseStreamReader responseReader =newStreamReader(webResponse.GetResponseStream());string fullResponse = responseReader.ReadToEnd();
    webResponse.Close();Response.Write(fullResponse);

    Building on dnolans example, this is the version I could actually get to work (there were some errors with the boundary, encoding wasn't set) :-)

    To send the data:

    HttpWebRequest oRequest =null;
    oRequest =(HttpWebRequest)HttpWebRequest.Create("http://you.url.here");
    oRequest.ContentType="multipart/form-data; boundary="+PostData.boundary;
    oRequest.Method="POST";PostData pData =newPostData();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();

    The PostData class should look like:

    publicclassPostData{// Change this if you need to, not necessarypublicstaticstring boundary ="AaB03x";privateList<PostDataParam> m_Params;publicList<PostDataParam>Params{
            get {return m_Params;}set{ m_Params = value;}}publicPostData(){
            m_Params =newList<PostDataParam>();}/// <summary>/// Returns the parameters array formatted for multi-part/form data/// </summary>/// <returns></returns>publicstringGetPostData(){StringBuilder sb =newStringBuilder();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();}}publicenumPostDataParamType{Field,File}publicclassPostDataParam{publicPostDataParam(string name,string value,PostDataParamType type){Name= name;Value= value;Type= type;}publicPostDataParam(string name,string filename,string value,PostDataParamType type){Name= name;Value= value;FileName= filename;Type= type;}publicstringName;publicstringFileName;publicstringValue;publicPostDataParamTypeType;}

    http://stackoverflow.com/questions/219827/multipart-forms-from-c-sharp-client
    namespace WindowsFormsApplication1{publicstaticclassFormUpload{privatestaticstringNewDataBoundary(){Random rnd =newRandom();string formDataBoundary ="";while(formDataBoundary.Length<15){
                    formDataBoundary = formDataBoundary + rnd.Next();}
                formDataBoundary = formDataBoundary.Substring(0,15);
                formDataBoundary ="-----------------------------"+ formDataBoundary;return formDataBoundary;}publicstaticHttpWebResponseMultipartFormDataPost(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=newCookieContainer();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 Streamstring 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 =newbyte[2048];FileStream fs =newFileStream(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 requestbyte[] footer =Encoding.UTF8.GetBytes("\r\n--"+ boundary +"--\r\n");
                    formDataStream.Write(footer,0, footer.Length);
                    request.ContentLength= formDataStream.Length;
                    formDataStream.Close();}#endregionreturn request.GetResponse()asHttpWebResponse;}}}

    参考

    C# Socket 实现的淘宝秒杀器(抢拍器)

    http://www.cnblogs.com/chengulv/archive/2013/01/25/2877383.html

  • 相关阅读:
    4年Java程序员十面阿里终拿下offer,评级P6+年薪30-40w无股票
    真香警告!手绘172张图解HTTP协议+703页TCP/IP协议笔记
    Git官方和创始人都推荐的Git权威指南,广度深度和实战性史无前例
    阿里“教授”总结整理手写大型网站技术架构:核心原理与案例分析
    GitHub上120K Stars国内第一的Java多线程PDF到底有什么魅力?
    霸榜GitHub必读书籍:编写高质量代码改善Java程序员的151个建议
    GitHub上260K Stars的P8架构师纯手写的Java高并发编程详解
    LeetCode每日一题:802 找到最终安全状态
    LeetCode每日一题:662二叉树最大宽度
    Springboot之security框架 登录安全验证授权流程
  • 原文地址:https://www.cnblogs.com/zcm123/p/3040584.html
Copyright © 2011-2022 走看看