Kirim file melalui HTTP POST dengan C #

96

Saya telah mencari dan membaca sekitar itu dan tidak dapat menemukan sesuatu yang benar-benar berguna.

Saya sedang menulis aplikasi C # win kecil yang memungkinkan pengguna mengirim file ke server web, bukan dengan FTP, tetapi dengan HTTP menggunakan POST. Anggap saja seperti formulir web tetapi berjalan pada aplikasi windows.

Saya memiliki objek HttpWebRequest saya yang dibuat menggunakan sesuatu seperti ini

HttpWebRequest req = WebRequest.Create(uri) as HttpWebRequest 

dan juga mengatur properti Method, ContentTypedan ContentLength. Tapi sejauh itu aku bisa pergi.

Ini adalah potongan kode saya:

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

Jadi pertanyaan saya pada dasarnya adalah bagaimana saya bisa mengirim fie (file teks, gambar, audio, dll) dengan C # melalui HTTP POST.

Terima kasih!

gabitoju.dll
sumber

Jawaban:

112

Menggunakan .NET 4.5 (atau .NET 4.0 dengan menambahkan paket Microsoft.Net.Http dari NuGet) ada cara yang lebih mudah untuk mensimulasikan permintaan formulir. Berikut ini contohnya:

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();
    }
}
Joshcodes
sumber
8
Jika memungkinkan bisa menunjukkan contoh sederhana memanggil metode ini?
Jacobr365
10
whats paramString parameter?
eran otzap
2
Terima kasih, contoh yang sangat lengkap! @eranotzap the paramString adalah nilai sebenarnya dari param yang akan dikirim. Argumen ketiga form.Addadalah opsional dan hanya berguna untuk file.
StockBreak
1
@ Liam, saya setuju sepenuhnya. Kode async dihapus dari jawaban 2013 saya agar semuanya tetap sederhana. Mengubahnya kembali ke metode async telah ada di daftar todo saya karena sebagian besar pengembang C # seharusnya sudah terbiasa dengannya pada saat ini.
Joshcodes
1
@Ammar, saya tidak menyadarinya, saya pikir Anda harus membaca file ke dalam aliran atau byte [] dan masing-masing menggunakan StreamContent atau ByteArrayContent.
Joshcodes
52

Untuk mengirim file mentah saja :

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

Jika Anda ingin meniru formulir browser dengan <input type="file"/>, maka itu lebih sulit. Lihat jawaban ini untuk jawaban yang multipart / form-data.

Marc Gravell
sumber
(tentu saja Anda dapat menambahkan header / kredensial / dll seperti biasa)
Marc Gravell
1
Terima kasih, saya telah menggunakannya dengan sesuatu yang sederhana dan tidak berhasil. Sekarang, seperti yang Anda katakan, saya perlu meniru file masukan browser, seperti ini <intput type = "file" name "userFile" />.
gabitoju
1
Saya telah menggunakan kode di atas dan mendapatkan kesalahan seperti: Argument pengecualian tidak ditangani oleh kode pengguna: {"format URI tidak didukung."}. Bagaimana saya bisa melakukan ini? dilindungi void Page_Load (pengirim objek, EventArgs e) {string address = "http: www.testproject.com/SavedFiles"; string filepath = @ "D: \ test \ FileOperations \ testfile.txt"; menggunakan (WebClient client = new WebClient ()) {client.UploadFile (address, filepath); }}
Sudha
1
@Sudha, apakah Anda sudah mencoba menggunakan alamat web yang sebenarnya? http://www.testproject.com/SavedFiles- perhatikan//
Marc Gravell
7

Bagi saya client.UploadFilemasih membungkus konten dalam permintaan multi bagian jadi saya harus melakukannya seperti ini:

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);
    }
}
Meelis Pruks
sumber
5

Saya mendapat masalah yang sama dan kode berikut ini menjawab dengan sempurna untuk masalah ini:

//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;
}
Thomas BLANCHET
sumber
bagaimana Anda menerima data dan menyimpan file ke disk di ujung lain?
KumarHarsh
3

Anda perlu menulis file Anda ke aliran permintaan:

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

Untuk memposting file sebagai dari array 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);
        }
    }
}
doker
sumber
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();
                }
            }
Masoud Siahkali
sumber
0

Menggunakan .NET 4.5 mencoba melakukan unggahan file bentuk POST. Mencoba sebagian besar metode di atas tetapi tidak berhasil. Temukan solusinya di sini https://www.c-sharpcorner.com/article/upload-any-file-using-http-post-multipart-form-data

Tetapi saya tidak tertarik karena saya tidak mengerti mengapa kita masih perlu berurusan dengan pemrograman tingkat rendah seperti itu dalam penggunaan umum ini (harus ditangani dengan baik oleh kerangka kerja)

bLaXjack
sumber