Can a POST request send a file at the same time, say XXX.txt to the server and a value for some field / variable, say "Ju2qQw". That is, I need to transfer a file to my server and at the same time some information related to this file. If this can be done, then please, indicate through what it can be done, if it is impossible - then what to use to solve this problem.

    3 answers 3

    Try this:

    string uri = "http://server.com/file"; string localPath = "/tmp/XXX.txt"; var parameters = new System.Collections.Specialized.NameValueCollection() { { "yourVariableName", "Ju2qQw" } }; using (var client = new WebClient()) { client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded"; client.QueryString = parameters; var responseBytes = client.UploadFile(uri, localPath); var response = Encoding.UTF8.GetString(responseBytes); } 

    (I'm not sure if this will work, I have nothing to try.)


    For the case when the server does not understand the parameters in the request, the code from this answer will do . I copy it here for convenience. Author code user en.SO Darin Dimitrov .

     public class UploadFile { public string Name; public string Filename; public string ContentType = "application/octet-stream"; public Stream Stream; } void SendAsciiString(string s, Stream stream) { var buffer = Encoding.ASCII.GetBytes(s); requestStream.Write(buffer, 0, buffer.Length); } void SendString(string s, Stream stream) { var buffer = Encoding.UTF8.GetBytes(s); requestStream.Write(buffer, 0, buffer.Length); } public byte[] UploadFiles( string uri, IEnumerable<UploadFile> files, NameValueCollection variables) { var request = WebRequest.Create(address); request.Method = "POST"; var boundary = new string('-', 27) + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo); request.ContentType = "multipart/form-data; boundary=" + boundary; boundary = "--" + boundary; var boundaryBytes = Encoding.ASCII.GetBytes(boundary + "\r\n"); using (var requestStream = request.GetRequestStream()) { // Write the values foreach (string name in values.Keys) { requestStream.Write(boundaryBytes, 0, boundaryBytes.Length); SendAsciiString(string.Format( "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n", name), requestStream); SendString(values[name] + "\r\n", requestStream); } // Write the files foreach (var file in files) { requestStream.Write(boundaryBytes, 0, boundaryBytes.Length); SendString(string.Format( "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n", file.Name, file.Filename), requestStream); SendAsciiString(string.Format( "Content-Type: {0}\r\n\r\n", file.ContentType), requestStream); file.Stream.CopyTo(requestStream); SendAsciiString("\r\n", requestStream); } SendAsciiString(boundary + "--\r\n", requestStream); } using (var response = request.GetResponse()) using (var responseStream = response.GetResponseStream()) using (var stream = new MemoryStream()) { responseStream.CopyTo(stream); return stream.ToArray(); } } 

    A similar approach is suggested in this article , some more links with similar content here .

    • Tested, works ?yourVariableName=Ju2qQw is present in the URL, the headers and contents of the file are also in place. - Regent
    • @Regent: Thank you! But still ask again. POST comes exactly? I am now reading this question , and the discussion says that it should not work, and we need custom implementation. Where is the catch? - VladD
    • On health. Yes, POST leaves, checked in Wireshark. I see no reason why the server may not be able to process the parameter specified in the URL. I did not carefully read into the heap of links from the specified answer, but I got the impression that all the problems were there due to the desire to push the data-parameters and the file into the request body - Regent
    • @Regent: Perhaps the code on that side is waiting for Content-Disposition: form-data; name="yourVariableName"\r\n\r\nJu2qQw Content-Disposition: form-data; name="yourVariableName"\r\n\r\nJu2qQw . But let it clarifies that OP. - VladD
    • @VladD depends on the code on that side. if there is any asp.net mvc, then the standard binder will normally pull out the value of yourVariableName from the GET line instead of the request body. If there is any php, then the code will wait for yourVariableName in the request body. - PashaPash

    Gentlemen, I found another solution to my problem - using a third-party xNet library. Maybe someone will be interested, here is a sample code for solving my problem.

     using (var request = new HttpRequest()) { var multipartContent = new MultipartContent() { {new StringContent("Bill Gates"), "login"}, {new StringContent("qwerthahaha"), "password"}, {new FileContent(@"C:\windows_9_alpha.rar"), "file1", "1.rar"} }; request.Post("www.microsoft.com", multipartContent).None(); } 

    An example is taken from here: http://habrahabr.ru/post/146475/

    • Looked at the xNet library. They have no async methods there at all! This means that each request will block at least one thread, which is not very comme il faut. However, +1. - VladD 2:21 pm
     async Task UploadFile(string url, byte[] bytes, string name, string filename = null) { using (var client = new System.Net.Http.HttpClient()) using (var content = new System.Net.Http.MultipartFormDataContent()) { content.Add(new System.Net.Http.StreamContent(new System.IO.MemoryStream(bytes)), name, filename ?? "q"); var result = await client.PostAsync(url, content); } }