[C#]使用WebClient上傳檔案並同時Post表單資料欄位到服務端
轉自:http://www.97world.com/archives/2963
之前遇到一個問題,就是使用WebClient上傳檔案的同時,還要Post表單資料欄位,一開始以為WebClient可以直接做到,結果發現如果先Post表單欄位,就只能獲取到欄位及其值,如果先上傳檔案,也只能獲取到上傳檔案的內容。測試了不少時間才發現WebClient不能這麼使用。
Google到相關的解決思路和類,因為發現網上的一些文章不是介紹得太簡單就是太複雜,所以這裡簡單整理一下,既能幫助自己鞏固知識,也希望能夠幫到大家!如果大家有什麼不明白,可以直接留言問我。
關於WebClient上傳檔案並同時Post表單資料的實現原理,大家可以參考這篇文章http://www.cnblogs.com/goody9807/archive/2007/06/06/773735.html,介紹得非常詳細,但是類和例項有些模糊,所以類和例項可以直接參考本文。
HttpRequestClient類Code:
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
using
System; using
System.Collections; using
System.Collections.Generic; using
System.Linq; using
System.IO; using
System.Text; using
System.Net; namespace
Common.Helper { /// <summary> /// description:http post請求客戶端 /// last-modified-date:2012-02-28 /// </summary> public
class HttpRequestClient { #region //欄位 private
ArrayList bytesArray; private
Encoding encoding = Encoding.UTF8; private
string boundary = String.Empty; #endregion #region //構造方法 public
HttpRequestClient() { bytesArray =
new ArrayList(); string
flag = DateTime.Now.Ticks.ToString( "x" ); boundary =
"---------------------------"
+ flag; } #endregion #region //方法 /// <summary> /// 合併請求資料 /// </summary> /// <returns></returns> private
byte [] MergeContent() { int
length = 0; int
readLength = 0; string
endBoundary = "--"
+ boundary + "--\r\n" ; byte [] endBoundaryBytes = encoding.GetBytes(endBoundary); bytesArray.Add(endBoundaryBytes); foreach
( byte [] b
in bytesArray) { length += b.Length; } byte [] bytes =
new byte [length]; foreach
( byte [] b
in bytesArray) { b.CopyTo(bytes, readLength); readLength += b.Length; } return
bytes; } /// <summary> /// 上傳 /// </summary> /// <param name="requestUrl">請求url</param> /// <param name="responseText">響應</param> /// <returns></returns> public
bool Upload(String requestUrl,
out String responseText) { WebClient webClient =
new WebClient(); webClient.Headers.Add( "Content-Type" ,
"multipart/form-data; boundary="
+ boundary); byte [] responseBytes; byte [] bytes = MergeContent(); try { responseBytes = webClient.UploadData(requestUrl, bytes); responseText = System.Text.Encoding.UTF8.GetString(responseBytes); return
true ; } catch
(WebException ex) { Stream responseStream = ex.Response.GetResponseStream(); responseBytes =
new byte [ex.Response.ContentLength]; responseStream.Read(responseBytes, 0, responseBytes.Length); } responseText = System.Text.Encoding.UTF8.GetString(responseBytes); return
false ; } /// <summary> /// 設定表單資料欄位 /// </summary> /// <param name="fieldName">欄位名</param> /// <param name="fieldValue">欄位值</param> /// <returns></returns> public
void SetFieldValue(String fieldName, String fieldValue) { string
httpRow = "--"
+ boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n" ; string
httpRowData = String.Format(httpRow, fieldName, fieldValue); bytesArray.Add(encoding.GetBytes(httpRowData)); } /// <summary> /// 設定表單檔案資料 /// </summary> /// <param name="fieldName">欄位名</param> /// <param name="filename">欄位值</param> /// <param name="contentType">內容內型</param> /// <param name="fileBytes">檔案位元組流</param> /// <returns></returns> public
void SetFieldValue(String fieldName, String filename, String contentType, Byte[] fileBytes) { string
end = "\r\n" ; string
httpRow = "--"
+ boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n" ; string
httpRowData = String.Format(httpRow, fieldName, filename, contentType); byte [] headerBytes = encoding.GetBytes(httpRowData); byte [] endBytes = encoding.GetBytes(end); byte [] fileDataBytes =
new byte [headerBytes.Length + fileBytes.Length + endBytes.Length]; headerBytes.CopyTo(fileDataBytes, 0); fileBytes.CopyTo(fileDataBytes, headerBytes.Length); endBytes.CopyTo(fileDataBytes, headerBytes.Length + fileBytes.Length); bytesArray.Add(fileDataBytes); } #endregion } } |
客戶端例項程式碼:
01
02
03
04
05
06
07
08
09
10
|
string
fileFullName= @"c:\test.txt" ,filedValue= "hello_world" ,responseText =
"" ; FileStream fs =
new FileStream(fileFullName, System.IO.FileMode.Open, System.IO.FileAccess.Read); byte [] fileBytes =
new byte [fs.Length]; fs.Read(fileBytes, 0, fileBytes.Length); fs.Close(); fs.Dispose(); HttpRequestClient httpRequestClient =
new HttpRequestClient(); httpRequestClient.SetFieldValue( "key" , filedValue); httpRequestClient.SetFieldValue( "uploadfile" , Path.GetFileName(fileFullName),
"application/octet-stream" , fileBytes); httpRequestClient.Upload(NormalBotConfig.Instance.GetUploadFileUrl(),
out responseText); |
服務端例項程式碼:
1
2
3
4
5
6
7
8
|
if
(HttpContext.Current.Request.Files.AllKeys.Length > 0) { string
filePath = Path.Combine(HttpContext.Current.Server.MapPath( "~/" ),
"UploadFile" , DateTime.Now.Year.ToString(), DateTime.Now.Month.ToString(), DateTime.Now.Day.ToString()); if
(!Directory.Exists(filePath)) Directory.CreateDirectory(filePath); //這裡我直接用索引來獲取第一個檔案,如果上傳了多個檔案,可以通過遍歷HttpContext.Current.Request.Files.AllKeys取“key值”,再通過HttpContext.Current.Request.Files[“key值”]獲取檔案 HttpContext.Current.Request.Files[0].SaveAs(Path.Combine(filePath, HttpContext.Current.Request.Files[0].FileName)); string
filedValue = HttpContext.Current.Request.Form[ "key" ]; } |
使用WebClient或HttpWebRequest模擬上傳檔案和資料
假如某網站有個表單,例如(url: http://localhost/login.aspx):
帳號
密碼
我們需要在程式中提交資料到這個表單,對於這種表單,我們可以使用 WebClient.UploadData 方法來實現,將所要上傳的資料拼成字元即可,程式很簡單:
string uriString = "http://localhost/login.aspx";
// 建立一個新的 WebClient 例項.
WebClient myWebClient = new WebClient();
string postData = "Username=admin&Password=admin";
// 注意這種拼字串的ContentType
myWebClient.Headers.Add("Content-Type","application/x-www-form-urlencoded");
// 轉化成二進位制陣列
byte[] byteArray = Encoding.ASCII.GetBytes(postData);
// 上傳資料,並獲取返回的二進位制資料.
byte[] responseArray = myWebClient.UploadData(uriString,"POST",byteArray);
對於檔案上傳類的表單,例如(url: http://localhost/uploadFile.aspx):
檔案
對於這種表單,我們可以使用
String uriString = "http://localhost/uploadFile.aspx";
// 建立一個新的 WebClient 例項.
WebClient myWebClient = new WebClient();
string fileName = @"C:\upload.txt";
// 直接上傳,並獲取返回的二進位制資料.
byte[] responseArray = myWebClient.UploadFile(uriString,"POST",fileName);
還有一種表單,不僅有文字,還有檔案,例如(url: http://localhost/uploadData.aspx):
檔名
檔案
對於這種表單,似乎前面的兩種方法都不能適用,對於第一種方法,不能直接拼字串,對於第二種,我們只能傳檔案,重新回到第一個方法,注意引數:
public byte[] UploadData(
string address,
string method,
byte[] data
);
在第一個例子中,是通過拼字串來得到byte[] data引數值的,對於這種表單顯然不行,反過來想想,對於uploadData.aspx這樣的程式來說,直接通過網頁提交資料,後臺所獲取到的流是什麼樣的呢?(在我以前的一篇blog中,曾分析過這個問題:asp無元件上傳進度條解決方案),最終的資料如下:
-----------------------------7d429871607fe
Content-Disposition: form-data; name="file1"; filename="G:\homepage.txt"
Content-Type: text/plain
寶玉:http://www.webuc.net
-----------------------------7d429871607fe
Content-Disposition: form-data; name="filename"
default filename
-----------------------------7d429871607fe--
所以只要拼一個這樣的byte[] data資料Post過去,就可以達到同樣的效果了。但是一定要注意,對於這種帶有檔案上傳的,其ContentType是不一樣的,例如上面的這種,其ContentType為"multipart/form-data; boundary=---------------------------7d429871607fe"。有了ContentType,我們就可以知道boundary(就是上面的"---------------------------7d429871607fe"),知道boundary了我們就可以構造出我們所需要的byte[] data了,最後,不要忘記,把我們構造的ContentType傳到WebClient中(例如:webClient.Headers.Add("Content-Type", ContentType);)這樣,就可以通過WebClient.UploadData 方法上載檔案資料了。
具體程式碼如下:
生成二進位制資料類的封裝
using System;
using System.Web;
using System.IO;
using System.Net;
using System.Text;
using System.Collections;
namespace UploadData.Common
{
/**//// <summary>
/// 建立WebClient.UploadData方法所需二進位制陣列
/// </summary>
public class CreateBytes
{
Encoding encoding = Encoding.UTF8;
/**//// <summary>
/// 拼接所有的二進位制陣列為一個陣列
/// </summary>
/// <param name="byteArrays">陣列</param>
/// <returns></returns>
/// <remarks>加上結束邊界</remarks>
public byte[] JoinBytes(ArrayList byteArrays)
{
int length = 0;
int readLength = 0;
// 加上結束邊界
string endBoundary = Boundary + "--\r\n"; //結束邊界
byte[] endBoundaryBytes = encoding.GetBytes(endBoundary);
byteArrays.Add(endBoundaryBytes);
foreach(byte[] b in byteArrays)
{
length += b.Length;
}
byte[] bytes = new byte[length];
// 遍歷複製
//
foreach(byte[] b in byteArrays)
{
b.CopyTo(bytes, readLength);
readLength += b.Length;
}
return bytes;
}
public bool UploadData(string uploadUrl, byte[] bytes, out byte[] responseBytes)
{
WebClient webClient = new WebClient();
webClient.Headers.Add("Content-Type", ContentType);
try
{
responseBytes = webClient.UploadData(uploadUrl, bytes);
return true;
}
catch (WebException ex)
{
Stream resp = ex.Response.GetResponseStream();
responseBytes = new byte[ex.Response.ContentLength];
resp.Read(responseBytes, 0, responseBytes.Length);
}
return false;
}
/**//// <summary>
/// 獲取普通表單區域二進位制陣列
/// </summary>
/// <param name="fieldName">表單名</param>
/// <param name="fieldValue">表單值</param>
/// <returns></returns>
/// <remarks>
/// -----------------------------7d52ee27210a3c\r\nContent-Disposition: form-data; name=\"表單名\"\r\n\r\n表單值\r\n
/// </remarks>
public byte[] CreateFieldData(string fieldName, string fieldValue)
{
string textTemplate = Boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n";
string text = String.Format(textTemplate, fieldName, fieldValue);
byte[] bytes = encoding.GetBytes(text);
return bytes;
}
/**//// <summary>
/// 獲取檔案上傳表單區域二進位制陣列
/// </summary>
/// <param name="fieldName">表單名</param>
/// <param name="filename">檔名</param>
/// <param name="contentType">檔案型別</param>
/// <param name="contentLength">檔案長度</param>
/// <param name="stream">檔案流</param>
/// <returns>二進位制陣列</returns>
public byte[] CreateFieldData(string fieldName, string filename,string contentType, byte[] fileBytes)
{
string end = "\r\n";
string textTemplate = Boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
// 頭資料
string data = String.Format(textTemplate, fieldName, filename, contentType);
byte[] bytes = encoding.GetBytes(data);
// 尾資料
byte[] endBytes = encoding.GetBytes(end);
// 合成後的陣列
byte[] fieldData = new byte[bytes.Length + fileBytes.Length + endBytes.Length];
bytes.CopyTo(fieldData, 0); // 頭資料
fileBytes.CopyTo(fieldData, bytes.Length); // 檔案的二進位制資料
endBytes.CopyTo(fieldData, bytes.Length + fileBytes.Length); // \r\n
return fieldData;
}
屬性屬性
}
}
在Winform中呼叫
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using UploadData.Common;
using System.IO;
namespace UploadDataWin
{
/**//// <summary>
/// frmUpload 的摘要說明。
/// </summary>
public class frmUpload : System.Windows.Forms.Form
{
private System.Windows.Forms.Label lblAmigoToken;
private System.Windows.Forms.TextBox txtAmigoToken;
private System.Windows.Forms.Label lblFilename;
private System.Windows.Forms.TextBox txtFilename;
private System.Windows.Forms.Button btnBrowse;
private System.Windows.Forms.TextBox txtFileData;
private System.Windows.Forms.Label lblFileData;
private System.Windows.Forms.Button btnUpload;
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private System.Windows.Forms.TextBox txtResponse;
/**//// <summary>
/// 必需的設計器變數。
/// </summary>
private System.ComponentModel.Container components = null;
public frmUpload()
{
//
// Windows 窗體設計器支援所必需的
//
InitializeComponent();
//
// TODO: 在 InitializeComponent 呼叫後新增任何建構函式程式碼
//
}
/**//// <summary>
/// 清理所有正在使用的資源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
Windows 窗體設計器生成的程式碼#region Windows 窗體設計器生成的程式碼
/**//// <summary>
/// 設計器支援所需的方法 - 不要使用程式碼編輯器修改
/// 此方法的內容。
/// </summary>
private void InitializeComponent()
{
this.lblAmigoToken = new System.Windows.Forms.Label();
this.txtAmigoToken = new System.Windows.Forms.TextBox();
this.lblFilename = new System.Windows.Forms.Label();
this.txtFilename = new System.Windows.Forms.TextBox();
this.btnBrowse = new System.Windows.Forms.Button();
this.txtFileData = new System.Windows.Forms.TextBox();
this.lblFileData = new System.Windows.Forms.Label();
this.btnUpload = new System.Windows.Forms.Button();
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
this.txtResponse = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// lblAmigoToken
//
this.lblAmigoToken.Location = new System.Drawing.Point(40, 48);
this.lblAmigoToken.Name = "lblAmigoToken";
this.lblAmigoToken.Size = new System.Drawing.Size(72, 23);
this.lblAmigoToken.TabIndex = 0;
this.lblAmigoToken.Text = "AmigoToken";
//
// txtAmigoToken
//
this.txtAmigoToken.Location = new System.Drawing.Point(120, 48);
this.txtAmigoToken.Name = "txtAmigoToken";
this.txtAmigoToken.Size = new System.Drawing.Size(248, 21);
this.txtAmigoToken.TabIndex = 1;
this.txtAmigoToken.Text = "";
//
// lblFilename
//
this.lblFilename.Location = new System.Drawing.Point(40, 96);
this.lblFilename.Name = "lblFilename";
this.lblFilename.Size = new System.Drawing.Size(80, 23);
this.lblFilename.TabIndex = 2;
this.lblFilename.Text = "Filename";
//
// txtFilename
//
this.txtFilename.Location = new System.Drawing.Point(120, 96);
this.txtFilename.Name = "txtFilename";
this.txtFilename.Size = new System.Drawing.Size(248, 21);
this.txtFilename.TabIndex = 3;
this.txtFilename.Text = "";
//
// btnBrowse
//
this.btnBrowse.Location = new System.Drawing.Point(296, 144);
this.btnBrowse.Name = "btnBrowse";
this.btnBrowse.TabIndex = 4;
this.btnBrowse.Text = "瀏覽";
this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
//
// txtFileData
//
this.txtFileData.Location = new System.Drawing.Point(120, 144);
this.txtFileData.Name = "txtFileData";
this.txtFileData.Size = new System.Drawing.Size(168, 21);
this.txtFileData.TabIndex = 5;
this.txtFileData.Text = "";
//
// lblFileData
//
this.lblFileData.Location = new System.Drawing.Point(40, 144);
this.lblFileData.Name = "lblFileData";
this.lblFileData.Size = new System.Drawing.Size(72, 23);
this.lblFileData.TabIndex = 6;
this.lblFileData.Text = "FileData";
//
// btnUpload
//
this.btnUpload.Location = new System.Drawing.Point(48, 184);
this.btnUpload.Name = "btnUpload";
this.btnUpload.TabIndex = 7;
this.btnUpload.Text = "Upload";
this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);
//
// txtResponse
//
this.txtResponse.Location = new System.Drawing.Point(136, 184);
this.txtResponse.Multiline = true;
this.txtResponse.Name = "txtResponse";
this.txtResponse.Size = new System.Drawing.Size(248, 72);
this.txtResponse.TabIndex = 8;
this.txtResponse.Text = "";
//
// frmUpload
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(400, 269);
this.Controls.Add(this.txtResponse);
this.Controls.Add(this.btnUpload);
this.Controls.Add(this.lblFileData);
this.Controls.Add(this.txtFileData);
this.Controls.Add(this.btnBrowse);
this.Controls.Add(this.txtFilename);
this.Controls.Add(this.lblFilename);
this.Controls.Add(this.txtAmigoToken);
this.Controls.Add(this.lblAmigoToken);
this.Name = "frmUpload";
this.Text = "frmUpload";
this.ResumeLayout(false);
}
#endregion
/**//// <summary>
/// 應用程式的主入口點。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new frmUpload());
}
private void btnUpload_Click(object sender, System.EventArgs e)
{
// 非空檢驗
if (txtAmigoToken.Text.Trim() == "" || txtFilename.Text == "" || txtFileData.Text.Trim() == "")
{
MessageBox.Show("Please fill data");
return;
}
// 所要上傳的檔案路徑
string path = txtFileData.Text.Trim();
// 檢查檔案是否存在
if (!File.Exists(path))
{
MessageBox.Show("{0} does not exist!", path);
return;
}
// 讀檔案流
FileStream fs = new FileStream(path, FileMode.Open,
FileAccess.Read, FileShare.Read);
// 這部分需要完善
string ContentType = "application/octet-stream";
byte[] fileBytes = new byte[fs.Length];
fs.Read(fileBytes, 0, Convert.ToInt32(fs.Length));
// 生成需要上傳的二進位制陣列
CreateBytes cb = new CreateBytes();
// 所有表單資料
ArrayList bytesArray = new ArrayList();
// 普通表單
bytesArray.Add(cb.CreateFieldData("FileName", txtFilename.Text));
bytesArray.Add(cb.CreateFieldData("AmigoToken", txtAmigoToken.Text));
// 檔案表單
bytesArray.Add(cb.CreateFieldData("FileData", path
, ContentType, fileBytes));
// 合成所有表單並生成二進位制陣列
byte[] bytes = cb.JoinBytes(bytesArray);
// 返回的內容
byte[] responseBytes;
// 上傳到指定Url
bool uploaded = cb.UploadData("http://localhost/UploadData/UploadAvatar.aspx", bytes, out responseBytes);
// 將返回的內容輸出到檔案
using (FileStream file = new FileStream(@"c:\response.text", FileMode.Create, FileAccess.Write, FileShare.Read))
{
file.Write(responseBytes, 0, responseBytes.Length);
}
txtResponse.Text = System.Text.Encoding.UTF8.GetString(responseBytes);
}
private void btnBrowse_Click(object sender, System.EventArgs e)
{
if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
txtFileData.Text = openFileDialog1.FileName;
}
}
}
}
相關文章
- post 表單大檔案上傳
- C# exe上傳檔案和提交表單資料的方法C#
- http不使用Form表單傳送檔案資料和非檔案資料(上傳篇)HTTPORM
- java Socket Tcp示例三則(服務端處理資料、上傳檔案)JavaTCP服務端
- Node.js:上傳檔案,服務端如何獲取檔案上傳進度Node.js服務端
- 把影像檔案上傳到資料庫,並從資料庫讀出 (轉)資料庫
- spring+hibernate檔案上傳並放入大欄位的處理Spring
- [Git命令]上傳單個檔案到GitHub專案已有資料夾Github
- python向後端Flask服務傳送檔案並在後端處理Python後端Flask
- git上傳到遠端有部分檔案未上傳Git
- 使用POST方法傳輸二進位制資料
- 上傳本地.CSV檔案到內表中
- 《如何將windows上的軟體包或檔案上傳到linux服務上》WindowsLinux
- Nodejs教程16:POST檔案上傳NodeJS
- 請問上傳的檔案如何傳送post
- 一個端到端的基於 form 表單的檔案上傳程式,包含客戶端和伺服器端ORM客戶端伺服器
- Docker下Java檔案上傳服務三部曲之二:服務端開發DockerJava服務端
- winfrom上傳多個檔案到指定資料夾
- CRM WebClient UI裡的檔案是如何上傳到Netweaver後臺的WebclientUI
- 單個檔案上傳和批量檔案上傳
- c# 上傳FTP檔案C#FTP
- C# httpclient上傳檔案C#HTTPclient
- FTP MPUT 關閉互動同時上傳多檔案FTP
- ASP中多檔案同時上傳解決方案 (轉)
- Python模擬HTTP Post上傳檔案PythonHTTP
- 用C#使用HttpWebRequest Post資料時如何保持SessionHTTPWebSession
- 觸發器—一個表更新資料時同步欄位到另一個表中觸發器
- SpringMVC 單檔案上傳與多檔案上傳SpringMVC
- ASP.NET Core 上傳檔案到共享資料夾ASP.NET
- 使用 JavaScript 上傳 PDF 和 Excel 等二進位制檔案到 ABAP 伺服器並進行解析JavaScriptExcel伺服器
- 利用DotNetZip服務端壓縮檔案並下載服務端
- jqm檔案上傳,上傳圖片,jqm的表單操作,jqm的ajax的使用,jqm檔案操作大全,檔案操作demo
- 分散式檔案上傳導致服務假死了?分散式
- 【SpringBoot】使用RestTemplate在服務之間進行MultipartFile格式檔案的傳遞【檔案上傳】Spring BootREST
- 實現服務端和客戶端的實時雙向資料傳輸-WebSocket簡單瞭解服務端客戶端Web
- 請教上傳檔案的同時,表單裡的引數不在可用的問題
- socket實現簡單傳檔案ftp/scp服務FTP
- 檔案上傳之後端黑白名單繞過後端