Gửi tệp qua HTTP POST với C #


95

Tôi đã tìm kiếm và đọc xung quanh điều đó và không thể thấy bất cứ điều gì thực sự hữu ích.

Tôi đang viết một ứng dụng C # win nhỏ cho phép người dùng gửi tệp đến máy chủ web, không phải bằng FTP mà bằng HTTP bằng POST. Hãy nghĩ về nó giống như một biểu mẫu web nhưng chạy trên một ứng dụng windows.

Tôi có đối tượng HttpWebRequest của mình được tạo bằng cách sử dụng thứ gì đó như thế này

HttpWebRequest req = WebRequest.Create(uri) as HttpWebRequest 

và cũng đặt Method, ContentTypeContentLengththuộc tính. Nhưng đó là xa tôi có thể đi.

Đây là đoạn mã của tôi:

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) 
{
}

Vì vậy, câu hỏi của tôi về cơ bản là làm thế nào tôi có thể gửi một fie (tệp văn bản, hình ảnh, âm thanh, v.v.) bằng C # qua HTTP POST.

Cảm ơn!


Câu trả lời:


112

Sử dụng .NET 4.5 (hoặc .NET 4.0 bằng cách thêm gói Microsoft.Net.Http từ NuGet) có một cách dễ dàng hơn để mô phỏng các yêu cầu biểu mẫu. Đây là một ví dụ:

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

8
Nếu có thể, có thể chỉ ra một ví dụ đơn giản về việc gọi phương thức này?
Jacobr365

10
tham số paramString là gì?
eran otzap

2
Cảm ơn bạn, ví dụ rất toàn diện! @eranotzap paramString là giá trị thực của param cần gửi. Đối số thứ ba form.Addtùy chọn và chỉ hữu ích cho các tệp.
StockBreak

1
@Liam, tôi hoàn toàn đồng ý. Mã không đồng bộ đã được xóa khỏi câu trả lời năm 2013 của tôi để giữ mọi thứ đơn giản. Thay đổi nó trở lại một phương thức không đồng bộ đã nằm trong danh sách việc cần làm của tôi vì hầu hết các nhà phát triển C # sẽ cảm thấy thoải mái với nó vào thời điểm này.
Joshcodes

1
@Ammar, tôi không biết, tôi nghĩ rằng bạn sẽ phải đọc tệp thành một luồng hoặc byte [] và sử dụng StreamContent hoặc ByteArrayContent tương ứng.
Joshcodes

51

Để gửi các tập tin thô chỉ :

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

Nếu bạn muốn mô phỏng một biểu mẫu trình duyệt với một <input type="file"/>, thì điều đó khó hơn. Xem câu trả lời này để biết câu trả lời đa phần / biểu mẫu-dữ liệu.


(tất nhiên bạn có thể thêm tiêu đề / thông tin đăng nhập / v.v. như bình thường)
Marc Gravell

1
Cảm ơn, tôi đã sử dụng nó với một cái gì đó đơn giản và tôi không hiệu quả. Bây giờ, như bạn nói, tôi cần mô phỏng một tệp đầu vào của trình duyệt, ví dụ như thế này <intput type = "file" name "userFile" />.
gabitoju,

1
Tôi đã sử dụng mã trên và gặp lỗi như: Ngoại lệ đối số không được xử lý bởi mã người dùng: {"Định dạng URI không được hỗ trợ."}. Tôi có thể làm cái này như thế nào? được bảo vệ void Page_Load (object sender, EventArgs e) {string address = "http: www.testproject.com/SavedFiles"; string filepath = @ "D: \ test \ FileOperations \ testfile.txt"; using (WebClient client = new WebClient ()) {client.UploadFile (address, filepath); }}
Sudha

1
@Sudha bạn đã thử sử dụng địa chỉ web thực chưa? http://www.testproject.com/SavedFiles- lưu ý//
Marc Gravell

7

Đối với tôi client.UploadFilevẫn gói nội dung trong một yêu cầu nhiều phần nên tôi phải làm như thế này:

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

5

Tôi đã gặp vấn đề tương tự và mã sau đây đã trả lời hoàn hảo cho vấn đề này:

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

Làm thế nào để bạn nhận dữ liệu và lưu tệp vào đĩa ở đầu bên kia?
KumarHarsh,

3

Bạn cần ghi tệp của mình vào luồng yêu cầu:

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

1

Để đăng tệp dưới dạng mảng byte:

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

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

0

Sử dụng .NET 4.5 cố gắng thực hiện tải lên tệp biểu mẫu POST. Đã thử hầu hết các phương pháp trên nhưng không có kết quả. Tìm thấy giải pháp ở đây https://www.c-sharpcorner.com/article/upload-any-file-using-http-post-multipart-form-data

Nhưng tôi không quan tâm vì tôi không hiểu tại sao chúng ta vẫn cần phải đối phó với lập trình cấp thấp như vậy trong những cách sử dụng phổ biến này (nên được xử lý tốt bằng khuôn khổ)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.