使用 C # 通过 HTTP POST 发送文件

我一直在到处寻找和阅读,但没有找到任何真正有用的东西。

我正在编写一个小的 C # win 应用程序,它允许用户发送文件到 Web 服务器,不是通过 FTP,而是通过 HTTP 使用 POST。可以把它想象成一个运行在 Windows 应用程序上的 web 表单。

我有我的 HttpWebRequest 对象创建使用这样的东西

HttpWebRequest req = WebRequest.Create(uri) as HttpWebRequest

也设置了 MethodContentTypeContentLength的属性。但是我只能做到这些。

这是我的密码:

HttpWebRequest req = WebRequest.Create(uri) as HttpWebRequest;
req.KeepAlive = false;
req.Method = "POST";
req.Credentials = new NetworkCredential(user.UserName, user.UserPassword);
req.PreAuthenticate = true;
req.ContentType = file.ContentType;
req.ContentLength = file.Length;
HttpWebResponse response = null;


try
{
response = req.GetResponse() as HttpWebResponse;
}
catch (Exception e)
{
}

因此,我的问题基本上就是如何通过 HTTP POST 使用 C # 发送一个文件(文本文件、图像、音频等)。

谢谢!

305322 次浏览

To send the raw file only:

using(WebClient client = new WebClient()) {
client.UploadFile(address, filePath);
}

If you want to emulate a browser form with an <input type="file"/>, then that is harder. See this answer for a multipart/form-data answer.

You need to write your file to the request stream:

using (var reqStream = req.GetRequestStream())
{
reqStream.Write( ... ) // write the bytes of the file
}

I had got the same problem and this following code answered perfectly at this problem :

//Identificate separator
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
//Encoding
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");


//Creation and specification of the request
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url); //sVal is id for the webService
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.KeepAlive = true;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;


string sAuthorization = "login:password";//AUTHENTIFICATION BEGIN
byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(sAuthorization);
string returnValue = System.Convert.ToBase64String(toEncodeAsBytes);
wr.Headers.Add("Authorization: Basic " + returnValue); //AUTHENTIFICATION END
Stream rs = wr.GetRequestStream();




string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}"; //For the POST's format


//Writting of the file
rs.Write(boundarybytes, 0, boundarybytes.Length);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(Server.MapPath("questions.pdf"));
rs.Write(formitembytes, 0, formitembytes.Length);


rs.Write(boundarybytes, 0, boundarybytes.Length);


string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = string.Format(headerTemplate, "file", "questions.pdf", contentType);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);


FileStream fileStream = new FileStream(Server.MapPath("questions.pdf"), FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
rs.Write(buffer, 0, bytesRead);
}
fileStream.Close();


byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
rs.Write(trailer, 0, trailer.Length);
rs.Close();
rs = null;


WebResponse wresp = null;
try
{
//Get the response
wresp = wr.GetResponse();
Stream stream2 = wresp.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
string responseData = reader2.ReadToEnd();
}
catch (Exception ex)
{
string s = ex.Message;
}
finally
{
if (wresp != null)
{
wresp.Close();
wresp = null;
}
wr = null;
}

Using .NET 4.5 (or .NET 4.0 by adding the Microsoft.Net.Http package from NuGet) there is an easier way to simulate form requests. Here is an example:

private async Task<System.IO.Stream> Upload(string actionUrl, string paramString, Stream paramFileStream, byte [] paramFileBytes)
{
HttpContent stringContent = new StringContent(paramString);
HttpContent fileStreamContent = new StreamContent(paramFileStream);
HttpContent bytesContent = new ByteArrayContent(paramFileBytes);
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
formData.Add(stringContent, "param1", "param1");
formData.Add(fileStreamContent, "file1", "file1");
formData.Add(bytesContent, "file2", "file2");
var response = await client.PostAsync(actionUrl, formData);
if (!response.IsSuccessStatusCode)
{
return null;
}
return await response.Content.ReadAsStreamAsync();
}
}

To post files as from byte arrays:

private static string UploadFilesToRemoteUrl(string url, IList<byte[]> files, NameValueCollection nvc) {


string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");


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


var formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";


foreach (string key in nvc.Keys) {
var formitem = string.Format(formdataTemplate, key, nvc[key]);
var formitembytes = Encoding.UTF8.GetBytes(formitem);
postQueue.Write(formitembytes);
}


var headerTemplate = "\r\n--" + boundary + "\r\n" +
"Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
"Content-Type: application/zip\r\n\r\n";


var i = 0;
foreach (var file in files) {
var header = string.Format(headerTemplate, "file" + i, "file" + i + ".zip");
var headerbytes = Encoding.UTF8.GetBytes(header);
postQueue.Write(headerbytes);
postQueue.Write(file);
i++;
}


postQueue.Write(Encoding.UTF8.GetBytes("\r\n--" + boundary + "--"));


request.ContentLength = postQueue.Length;


using (var requestStream = request.GetRequestStream()) {
postQueue.CopyToStream(requestStream);
requestStream.Close();
}


var webResponse2 = request.GetResponse();


using (var stream2 = webResponse2.GetResponseStream())
using (var reader2 = new StreamReader(stream2)) {


var res =  reader2.ReadToEnd();
webResponse2.Close();
return res;
}
}


public class ByteArrayCustomQueue {


private LinkedList<byte[]> arrays = new LinkedList<byte[]>();


/// <summary>
/// Writes the specified data.
/// </summary>
/// <param name="data">The data.</param>
public void Write(byte[] data) {
arrays.AddLast(data);
}


/// <summary>
/// Gets the length.
/// </summary>
/// <value>
/// The length.
/// </value>
public int Length { get { return arrays.Sum(x => x.Length); } }


/// <summary>
/// Copies to stream.
/// </summary>
/// <param name="requestStream">The request stream.</param>
/// <exception cref="System.NotImplementedException"></exception>
public void CopyToStream(Stream requestStream) {
foreach (var array in arrays) {
requestStream.Write(array, 0, array.Length);
}
}
}

For me client.UploadFile still wrapped the content in a multipart request so I had to do it like this:

using (WebClient client = new WebClient())
{
client.Headers.Add("Content-Type", "application/octet-stream");
using (Stream fileStream = File.OpenRead(filePath))
using (Stream requestStream = client.OpenWrite(new Uri(fileUploadUrl), "POST"))
{
fileStream.CopyTo(requestStream);
}
}
     public string SendFile(string filePath)
{
WebResponse response = null;
try
{
string sWebAddress = "Https://www.address.com";


string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(sWebAddress);
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.KeepAlive = true;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream stream = wr.GetRequestStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";


stream.Write(boundarybytes, 0, boundarybytes.Length);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(filePath);
stream.Write(formitembytes, 0, formitembytes.Length);
stream.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = string.Format(headerTemplate, "file", Path.GetFileName(filePath), Path.GetExtension(filePath));
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
stream.Write(headerbytes, 0, headerbytes.Length);


FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
stream.Write(buffer, 0, bytesRead);
fileStream.Close();


byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
stream.Write(trailer, 0, trailer.Length);
stream.Close();


response = wr.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(responseStream);
string responseData = streamReader.ReadToEnd();
return responseData;
}
catch (Exception ex)
{
return ex.Message;
}
finally
{
if (response != null)
response.Close();
}
}

Using .NET 4.5 trying to perform form POST file upload. Tried most of the methods above but to no avail. Found the solution here https://www.c-sharpcorner.com/article/upload-any-file-using-http-post-multipart-form-data

But I am not not keen as I do not understand why we still need to deal with such low level programming in these common usages (should be handled nicely by framework)

You can do it directly with HttpWebRequest/HttpWebResponse like this.

        string serviceUrl = string.Format("{0}/upload?param={1}", "http://127.0.0.1:8080", HttpUtility.UrlEncode(parameter));
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serviceUrl);
request.Method = "POST";
request.KeepAlive = true;
        

FileStream file = File.OpenRead(pathToFile);
request.ContentLength = file.Length;


file.Seek(0, SeekOrigin.Begin);
file.CopyTo(request.GetRequestStream());


HttpWebResponse response = (request.GetResponse() as HttpWebResponse);
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string responseText = reader.ReadToEnd();