111 votes

Envoyer un fichier via POST HTTP avec C#

J'ai cherché et lu à ce sujet, mais je n'ai rien trouvé de vraiment utile.

Je suis en train d'écrire une petite application C# Windows qui permet à l'utilisateur d'envoyer des fichiers à un serveur web, non pas par FTP, mais par HTTP en utilisant POST. Pensez à un formulaire web mais exécuté dans une application Windows.

J'ai créé mon objet HttpWebRequest en utilisant quelque chose comme ceci :

HttpWebRequest req = WebRequest.Create(uri) as HttpWebRequest 

et j'ai également défini les propriétés Method, ContentType et ContentLength. Mais c'est tout ce que je peux faire.

Voici mon morceau de 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) 
{
}

Ma question est donc essentiellement comment puis-je envoyer un fichier (fichier texte, image, audio, etc.) avec C# via HTTP POST.

Merci !

131voto

Joshcodes Points 1411

En utilisant .NET 4.5 (ou .NET 4.0 en ajoutant le paquet Microsoft.Net.Http depuis NuGet), il y a une manière plus facile de simuler des requêtes de formulaire. Voici un exemple :

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

59voto

Marc Gravell Points 482669

Pour envoyer le fichier brut seulement :

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

Si vous voulez simuler un formulaire de navigateur avec un , alors c'est plus difficile. Voir cette réponse pour une réponse multipart/form-data.

10voto

Meelis Pruks Points 99

Pour moi client.UploadFile enroulait toujours le contenu dans une demande multipart, je devais donc le faire comme ceci :

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

6voto

Thomas BLANCHET Points 143

J'avais le même problème et ce code suivant a parfaitement répondu à ce problème :

//Identificateur du séparateur
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
//Encodage
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

//Création et spécification de la requête
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url); //sVal est l'id pour le 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}"; //Pour le format POST

//Écriture du fichier
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
{
    //Obtenir la réponse
    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;
}

3voto

Pop Catalin Points 25033

Vous devez écrire votre fichier dans le flux de requête :

using (var reqStream = req.GetRequestStream()) 
{    
    reqStream.Write( ... ) // écrire les octets du fichier
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X