在基于Http协议的Post请求中,Content-type为application/x-www-form-urlencoded的传输只能传送非文件的数据。
如果想用Http的Post方法来上传数据及文件,需要实现Content-type为multipart/form-data类型的协议程序。
下面是参考了StackOverflow网站上的一个例子,实现了关于客户端上传文件的功能类,代码如下:
001 | using System; |
002 | using System.Net; |
003 | using System.Text; |
004 | using System.Collections.Generic; |
005 | using System.IO; |
006 |
007 | namespace ZDWorks.ZDClock.Cloud |
008 | { |
009 | /// <summary> |
010 | /// 文件类型数据的内容参数 |
011 | /// </summary> |
012 | public class FileParameter |
013 | { |
014 | // 文件内容 |
015 | public byte [] File { get ; set ; } |
016 | // 文件名 |
017 | public string FileName { get ; set ; } |
018 | // 文件内容类型 |
019 | public string ContentType { get ; set ; } |
020 |
021 | public FileParameter( byte [] file) : this (file, null ) { } |
022 |
023 | public FileParameter( byte [] file, string filename) : this (file, filename, null ) { } |
024 |
025 | public FileParameter( byte [] file, string filename, string contentType) |
026 | { |
027 | File = file; |
028 | FileName = filename; |
029 | ContentType = contentType; |
030 | } |
031 | } |
032 |
033 | /// <summary> |
034 | /// 数据与文件http请求 |
035 | /// </summary> |
036 | public class HttpMultipartFormRequest |
037 | { |
038 | #region Data Members |
039 |
040 | private readonly Encoding DefaultEncoding = Encoding.UTF8; |
041 | private ResponseCallback m_Callback; |
042 | private byte [] m_FormData; |
043 |
044 | #endregion |
045 |
046 | #region Constructor |
047 |
048 | public HttpMultipartFormRequest() |
049 | { |
050 | } |
051 |
052 | #endregion |
053 |
054 | #region Delegate |
055 |
056 | public delegate void ResponseCallback( string msg); |
057 |
058 | #endregion |
059 |
060 | public void AsyncHttpRequest( string postUri, Dictionary< string , object > postParameters, ResponseCallback callback) |
061 | { |
062 | // 随机序列,用作防止服务器无法识别数据的起始位置 |
063 | string formDataBoundary = String.Format( "----------{0:N}" , Guid.NewGuid()); |
064 | // 设置contentType |
065 | string contentType = "multipart/form-data; boundary=" + formDataBoundary; |
066 | // 将数据转换为byte[]格式 |
067 | m_FormData = GetMultipartFormData(postParameters, formDataBoundary); |
068 | // 回调函数 |
069 | m_Callback = callback; |
070 |
071 | // 创建http对象 |
072 | HttpWebRequest request = HttpWebRequest.CreateHttp( new Uri(postUri)); |
073 | // 设为post请求 |
074 | request.Method = "POST" ; |
075 | request.ContentType = contentType; |
076 | // 请求写入数据流 |
077 | request.BeginGetRequestStream(GetRequestStreamCallback, request); |
078 | } |
079 |
080 | private void GetRequestStreamCallback(IAsyncResult ar) |
081 | { |
082 | HttpWebRequest request = ar.AsyncState as HttpWebRequest; |
083 | using (var postStream = request.EndGetRequestStream(ar)) |
084 | { |
085 | postStream.Write(m_FormData, 0, m_FormData.Length); |
086 | postStream.Close(); |
087 | } |
088 | request.BeginGetResponse(GetResponseCallback, request); |
089 | } |
090 |
091 | private void GetResponseCallback(IAsyncResult ar) |
092 | { |
093 | // 处理Post请求返回的消息 |
094 | try |
095 | { |
096 | HttpWebRequest request = ar.AsyncState as HttpWebRequest; |
097 | HttpWebResponse response = request.EndGetResponse(ar) as HttpWebResponse; |
098 | using (var stream = response.GetResponseStream()) |
099 | { |
100 | StreamReader reader = new StreamReader(stream); |
101 | string msg = reader.ReadToEnd(); |
102 |
103 | if (m_Callback != null ) |
104 | { |
105 | m_Callback(msg); |
106 | } |
107 | } |
108 | } |
109 | catch (Exception e) |
110 | { |
111 | string a = e.ToString(); |
112 | if (m_Callback != null ) |
113 | { |
114 | m_Callback( string .Empty); |
115 | } |
116 | } |
117 | } |
118 |
119 | private byte [] GetMultipartFormData(Dictionary< string , object > postParameters, string boundary) |
120 | { |
121 | Stream formDataStream = new MemoryStream(); |
122 | bool needsCLRF = false ; |
123 |
124 | foreach (var param in postParameters) |
125 | { |
126 | if (needsCLRF) |
127 | { |
128 | formDataStream.Write(DefaultEncoding.GetBytes( "\r\n" ), 0, DefaultEncoding.GetByteCount( "\r\n" )); |
129 | } |
130 | needsCLRF = true ; |
131 |
132 | if (param.Value is FileParameter) |
133 | { |
134 | FileParameter fileToUpload = (FileParameter)param.Value; |
135 |
136 | string header = string .Format( "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n" , |
137 | boundary, |
138 | param.Key, |
139 | fileToUpload.FileName ?? param.Key, |
140 | fileToUpload.ContentType ?? "application/octet-stream" ); |
141 |
142 | // 将与文件相关的header数据写到stream中 |
143 | formDataStream.Write(DefaultEncoding.GetBytes(header), 0, DefaultEncoding.GetByteCount(header)); |
144 | // 将文件数据直接写到stream中 |
145 | formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length); |
146 | } |
147 | else |
148 | { |
149 | string postData = string .Format( "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}" , |
150 | boundary, |
151 | param.Key, |
152 | param.Value); |
153 | formDataStream.Write(DefaultEncoding.GetBytes(postData), 0, DefaultEncoding.GetByteCount(postData)); |
154 | } |
155 | } |
156 |
157 | string tailEnd = "\r\n--" + boundary + "--\r\n" ; |
158 | formDataStream.Write(DefaultEncoding.GetBytes(tailEnd), 0, DefaultEncoding.GetByteCount(tailEnd)); |
159 |
160 | // 将Stream数据转换为byte[]格式 |
161 | formDataStream.Position = 0; |
162 | byte [] formData = new byte [formDataStream.Length]; |
163 | formDataStream.Read(formData, 0, formData.Length); |
164 | formDataStream.Close(); |
165 |
166 | return formData; |
167 | } |
168 | } |
169 | } |