Senden Sie eine Datei über HTTP POST mit C #

95

Ich habe danach gesucht und gelesen und konnte nichts wirklich Nützliches bestrafen.

Ich schreibe eine kleine C # Win-App, mit der Benutzer Dateien nicht per FTP, sondern per HTTP mithilfe von POST an einen Webserver senden können. Stellen Sie sich das wie ein Webformular vor, das jedoch in einer Windows-Anwendung ausgeführt wird.

Ich habe mein HttpWebRequest-Objekt mit so etwas erstellt

HttpWebRequest req = WebRequest.Create(uri) as HttpWebRequest 

und auch die festgelegt Method, ContentTypeund ContentLengthEigenschaften. Aber so weit kann ich gehen.

Das ist mein Code:

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

Meine Frage ist also im Grunde, wie ich eine Nachricht (Textdatei, Bild, Audio usw.) mit C # über HTTP POST senden kann.

Vielen Dank!

gabitoju
quelle
1
Bitte überprüfen Sie stackoverflow.com/questions/15738847/…
Sudha

Antworten:

112

Mit .NET 4.5 (oder .NET 4.0 durch Hinzufügen des Microsoft.Net.Http- Pakets von NuGet) können Formularanforderungen einfacher simuliert werden. Hier ist ein Beispiel:

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
quelle
8
Wenn möglich, könnte ein einfaches Beispiel für den Aufruf dieser Methode gezeigt werden?
Jacobr365
10
Was ist der Parameter paramString?
eran otzap
2
Vielen Dank, sehr umfassendes Beispiel! @eranotzap Der paramString ist der tatsächliche Wert des zu sendenden Parameters. Das dritte Argument form.Addist optional und nur für Dateien nützlich.
StockBreak
1
@ Liam, ich stimme voll und ganz zu. Der asynchrone Code wurde aus meiner Antwort von 2013 entfernt, um die Dinge einfach zu halten. Das Zurücksetzen auf eine asynchrone Methode stand auf meiner Aufgabenliste, da die meisten C # -Entwickler an dieser Stelle damit vertraut sein sollten.
Joshcodes
1
@Ammar, das ist mir nicht bekannt, ich denke, Sie müssten die Datei in einen Stream oder ein Byte [] einlesen und StreamContent bzw. ByteArrayContent verwenden.
Joshcodes
51

Um die RAW - Datei sendet nur :

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

Wenn Sie ein Browserformular mit einem emulieren möchten <input type="file"/>, ist dies schwieriger. In dieser Antwort finden Sie eine mehrteilige / Formulardaten-Antwort.

Marc Gravell
quelle
(Sie können natürlich wie
gewohnt
1
Danke, ich habe es mit etwas Einfachem benutzt und ich habe nicht gearbeitet. Wie Sie sagen, muss ich jetzt eine Browser-Eingabedatei emulieren, etwa <intput type = "file" name "userFile" />.
Gabitoju
1
Ich habe den obigen Code verwendet und folgende Fehlermeldung erhalten: Die Argumentausnahme wurde vom Benutzercode nicht behandelt: {"URI-Formate werden nicht unterstützt."}. Wie kann ich das machen? protected void Page Load (Objektabsender, EventArgs e) {string address = "http: www.testproject.com/SavedFiles"; Zeichenfolge filepath = @ "D: \ test \ FileOperations \ testfile.txt"; using (WebClient client = new WebClient ()) {client.UploadFile (Adresse, Dateipfad); }}
Sudha
1
@ Sudha haben Sie versucht, eine tatsächliche Webadresse zu verwenden? http://www.testproject.com/SavedFiles- Beachten Sie die//
Marc Gravell
7

Für mich war client.UploadFileder Inhalt immer noch in eine mehrteilige Anfrage eingewickelt, also musste ich es so machen:

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
quelle
5

Ich hatte das gleiche Problem und dieser folgende Code antwortete perfekt auf dieses 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;
}
Thomas BLANCHET
quelle
Wie erhalten Sie die Daten und speichern die Datei auf der Festplatte am anderen Ende?
KumarHarsh
3

Sie müssen Ihre Datei in den Anforderungsdatenstrom schreiben:

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

So veröffentlichen Sie Dateien aus 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);
        }
    }
}
Doker
quelle
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
quelle
0

Verwenden von .NET 4.5, um den Upload von Formular-POST-Dateien durchzuführen. Versuchte die meisten der oben genannten Methoden, aber ohne Erfolg. Die Lösung finden Sie hier https://www.c-sharpcorner.com/article/upload-any-file-using-http-post-multipart-form-data

Aber ich bin nicht begeistert, da ich nicht verstehe, warum wir uns in diesen allgemeinen Verwendungen immer noch mit solch niedriger Programmierung befassen müssen (sollte vom Framework gut gehandhabt werden).

bLaXjack
quelle