Upload files with HTTPWebrequest (multipart/form-data)

后端 未结 21 2562
独厮守ぢ
独厮守ぢ 2020-11-21 04:53

Is there any class, library or some piece of code which will help me to upload files with HTTPWebrequest?

Edit 2:

I do not

相关标签:
21条回答
  • 2020-11-21 05:08

    There is another working example with some my comments :

            List<MimePart> mimeParts = new List<MimePart>();
    
            try
            {
                foreach (string key in form.AllKeys)
                {
                    StringMimePart part = new StringMimePart();
    
                    part.Headers["Content-Disposition"] = "form-data; name=\"" + key + "\"";
                    part.StringData = form[key];
    
                    mimeParts.Add(part);
                }
    
                int nameIndex = 0;
    
                foreach (UploadFile file in files)
                {
                    StreamMimePart part = new StreamMimePart();
    
                    if (string.IsNullOrEmpty(file.FieldName))
                        file.FieldName = "file" + nameIndex++;
    
                    part.Headers["Content-Disposition"] = "form-data; name=\"" + file.FieldName + "\"; filename=\"" + file.FileName + "\"";
                    part.Headers["Content-Type"] = file.ContentType;
    
                    part.SetStream(file.Data);
    
                    mimeParts.Add(part);
                }
    
                string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
    
                req.ContentType = "multipart/form-data; boundary=" + boundary;
                req.Method = "POST";
    
                long contentLength = 0;
    
                byte[] _footer = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n");
    
                foreach (MimePart part in mimeParts)
                {
                    contentLength += part.GenerateHeaderFooterData(boundary);
                }
    
                req.ContentLength = contentLength + _footer.Length;
    
                byte[] buffer = new byte[8192];
                byte[] afterFile = Encoding.UTF8.GetBytes("\r\n");
                int read;
    
                using (Stream s = req.GetRequestStream())
                {
                    foreach (MimePart part in mimeParts)
                    {
                        s.Write(part.Header, 0, part.Header.Length);
    
                        while ((read = part.Data.Read(buffer, 0, buffer.Length)) > 0)
                            s.Write(buffer, 0, read);
    
                        part.Data.Dispose();
    
                        s.Write(afterFile, 0, afterFile.Length);
                    }
    
                    s.Write(_footer, 0, _footer.Length);
                }
    
                return (HttpWebResponse)req.GetResponse();
            }
            catch
            {
                foreach (MimePart part in mimeParts)
                    if (part.Data != null)
                        part.Data.Dispose();
    
                throw;
            }
    

    And there is example of using :

                UploadFile[] files = new UploadFile[] 
                { 
                    new UploadFile(@"C:\2.jpg","new_file","image/jpeg") //new_file is id of upload field
                };
    
                NameValueCollection form = new NameValueCollection();
    
                form["id_hidden_input"] = "value_hidden_inpu"; //there is additional param (hidden fields on page)
    
    
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(full URL of action);
    
                // set credentials/cookies etc. 
                req.CookieContainer = hrm.CookieContainer; //hrm is my class. i copied all cookies from last request to current (for auth)
                HttpWebResponse resp = HttpUploadHelper.Upload(req, files, form);
    
                using (Stream s = resp.GetResponseStream())
                using (StreamReader sr = new StreamReader(s))
                {
                    string response = sr.ReadToEnd();
                }
                 //profit!
    
    0 讨论(0)
  • 2020-11-21 05:09

    VB Example (converted from C# example on another post):

    Private Sub HttpUploadFile( _
        ByVal uri As String, _
        ByVal filePath As String, _
        ByVal fileParameterName As String, _
        ByVal contentType As String, _
        ByVal otherParameters As Specialized.NameValueCollection)
    
        Dim boundary As String = "---------------------------" & DateTime.Now.Ticks.ToString("x")
        Dim newLine As String = System.Environment.NewLine
        Dim boundaryBytes As Byte() = Text.Encoding.ASCII.GetBytes(newLine & "--" & boundary & newLine)
        Dim request As Net.HttpWebRequest = Net.WebRequest.Create(uri)
    
        request.ContentType = "multipart/form-data; boundary=" & boundary
        request.Method = "POST"
        request.KeepAlive = True
        request.Credentials = Net.CredentialCache.DefaultCredentials
    
        Using requestStream As IO.Stream = request.GetRequestStream()
    
            Dim formDataTemplate As String = "Content-Disposition: form-data; name=""{0}""{1}{1}{2}"
    
            For Each key As String In otherParameters.Keys
    
                requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
                Dim formItem As String = String.Format(formDataTemplate, key, newLine, otherParameters(key))
                Dim formItemBytes As Byte() = Text.Encoding.UTF8.GetBytes(formItem)
                requestStream.Write(formItemBytes, 0, formItemBytes.Length)
    
            Next key
    
            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
    
            Dim headerTemplate As String = "Content-Disposition: form-data; name=""{0}""; filename=""{1}""{2}Content-Type: {3}{2}{2}"
            Dim header As String = String.Format(headerTemplate, fileParameterName, filePath, newLine, contentType)
            Dim headerBytes As Byte() = Text.Encoding.UTF8.GetBytes(header)
            requestStream.Write(headerBytes, 0, headerBytes.Length)
    
            Using fileStream As New IO.FileStream(filePath, IO.FileMode.Open, IO.FileAccess.Read)
    
                Dim buffer(4096) As Byte
                Dim bytesRead As Int32 = fileStream.Read(buffer, 0, buffer.Length)
    
                Do While (bytesRead > 0)
    
                    requestStream.Write(buffer, 0, bytesRead)
                    bytesRead = fileStream.Read(buffer, 0, buffer.Length)
    
                Loop
    
            End Using
    
            Dim trailer As Byte() = Text.Encoding.ASCII.GetBytes(newLine & "--" + boundary + "--" & newLine)
            requestStream.Write(trailer, 0, trailer.Length)
    
        End Using
    
        Dim response As Net.WebResponse = Nothing
    
        Try
    
            response = request.GetResponse()
    
            Using responseStream As IO.Stream = response.GetResponseStream()
    
                Using responseReader As New IO.StreamReader(responseStream)
    
                    Dim responseText = responseReader.ReadToEnd()
                    Diagnostics.Debug.Write(responseText)
    
                End Using
    
            End Using
    
        Catch exception As Net.WebException
    
            response = exception.Response
    
            If (response IsNot Nothing) Then
    
                Using reader As New IO.StreamReader(response.GetResponseStream())
    
                    Dim responseText = reader.ReadToEnd()
                    Diagnostics.Debug.Write(responseText)
    
                End Using
    
                response.Close()
    
            End If
    
        Finally
    
            request = Nothing
    
        End Try
    
    End Sub
    
    0 讨论(0)
  • 2020-11-21 05:11

    UPDATE: Using .NET 4.5 (or .NET 4.0 by adding the Microsoft.Net.Http package from NuGet) this is possible without external code, extensions, and "low level" HTTP manipulation. Here is an example:

    // Perform the equivalent of posting a form with a filename and two files, in HTML:
    // <form action="{url}" method="post" enctype="multipart/form-data">
    //     <input type="text" name="filename" />
    //     <input type="file" name="file1" />
    //     <input type="file" name="file2" />
    // </form>
    private async Task<System.IO.Stream> UploadAsync(string url, string filename, Stream fileStream, byte [] fileBytes)
    {
        // Convert each of the three inputs into HttpContent objects
    
        HttpContent stringContent = new StringContent(filename);
        // examples of converting both Stream and byte [] to HttpContent objects
        // representing input type file
        HttpContent fileStreamContent = new StreamContent(fileStream);
        HttpContent bytesContent = new ByteArrayContent(fileBytes);
    
        // Submit the form using HttpClient and 
        // create form data as Multipart (enctype="multipart/form-data")
    
        using (var client = new HttpClient())
        using (var formData = new MultipartFormDataContent()) 
        {
            // Add the HttpContent objects to the form data
    
            // <input type="text" name="filename" />
            formData.Add(stringContent, "filename", "filename");
            // <input type="file" name="file1" />
            formData.Add(fileStreamContent, "file1", "file1");
            // <input type="file" name="file2" />
            formData.Add(bytesContent, "file2", "file2");
    
            // Invoke the request to the server
    
            // equivalent to pressing the submit button on
            // a form with attributes (action="{url}" method="post")
            var response = await client.PostAsync(url, formData);
    
            // ensure the request was a success
            if (!response.IsSuccessStatusCode)
            {
                return null;
            }
            return await response.Content.ReadAsStreamAsync();
        }
    }
    
    0 讨论(0)
  • 2020-11-21 05:11

    I had to deal with this recently - another way to approach it is to use the fact that WebClient is inheritable, and change the underlying WebRequest from there:

    http://msdn.microsoft.com/en-us/library/system.net.webclient.getwebrequest(VS.80).aspx

    I prefer C#, but if you're stuck with VB the results will look something like this:

    Public Class BigWebClient
        Inherits WebClient
        Protected Overrides Function GetWebRequest(ByVal address As System.Uri) As System.Net.WebRequest
            Dim x As WebRequest = MyBase.GetWebRequest(address)
            x.Timeout = 60 * 60 * 1000
            Return x
        End Function
    End Class
    
    'Use BigWebClient here instead of WebClient
    
    0 讨论(0)
  • 2020-11-21 05:11

    I can never get the examples to work properly, I always receive a 500 error when sending it to the server.

    However I came across a very elegant method of doing it in this url

    It is easily extendible and obviously works with binary files as well as XML.

    You call it using something similar to this

    class Program
    {
        public static string gsaFeedURL = "http://yourGSA.domain.com:19900/xmlfeed";
    
        static void Main()
        {
            try
            {
                postWebData();
            }
            catch (Exception ex)
            {
            }
        }
    
        // new one I made from C# web service
        public static void postWebData()
        {
            StringDictionary dictionary = new StringDictionary();
            UploadSpec uploadSpecs = new UploadSpec();
            UTF8Encoding encoding = new UTF8Encoding();
            byte[] bytes;
            Uri gsaURI = new Uri(gsaFeedURL);  // Create new URI to GSA feeder gate
            string sourceURL = @"C:\FeedFile.xml"; // Location of the XML feed file
            // Two parameters to send
            string feedtype = "full";
            string datasource = "test";            
    
            try
            {
                // Add the parameter values to the dictionary
                dictionary.Add("feedtype", feedtype);
                dictionary.Add("datasource", datasource);
    
                // Load the feed file created and get its bytes
                XmlDocument xml = new XmlDocument();
                xml.Load(sourceURL);
                bytes = Encoding.UTF8.GetBytes(xml.OuterXml);
    
                // Add data to upload specs
                uploadSpecs.Contents = bytes;
                uploadSpecs.FileName = sourceURL;
                uploadSpecs.FieldName = "data";
    
                // Post the data
                if ((int)HttpUpload.Upload(gsaURI, dictionary, uploadSpecs).StatusCode == 200)
                {
                    Console.WriteLine("Successful.");
                }
                else
                {
                    // GSA POST not successful
                    Console.WriteLine("Failure.");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-21 05:12

    I was looking to do file upload and add some parameters to a multipart/form-data request in VB.NET and not through a regular forms post. Thanks to @JoshCodes answer I got the direction I was looking for. I am posting my solution to help others find a way to perform a post with both file and parameters the html equivalent of what I try to achieve is : html

    <form action="your-api-endpoint" enctype="multipart/form-data" method="post"> 
    <input type="hidden" name="action" value="api-method-name"/> 
    <input type="hidden" name="apiKey" value="gs1xxxxxxxxxxxxxex"/> 
    <input type="hidden" name="access" value="protected"/> 
    <input type="hidden" name="name" value="test"/> 
    <input type="hidden" name="title" value="test"/> 
    <input type="hidden" name="signature" value="cf1d4xxxxxxxxcd5"/> 
    <input type="file" name="file"/> 
    <input type="submit" name="_upload" value="Upload"/> 
    </form>
    

    Due to the fact that I have to provide the apiKey and the signature (which is a calculated checksum of the request parameters and api key concatenated string), I needed to do it server side. The other reason I needed to do it server side is the fact that the post of the file can be performed at any time by pointing to a file already on the server (providing the path), so there would be no manually selected file during form post thus form data file would not contain the file stream.Otherwise I could have calculated the checksum via an ajax callback and submitted the file through the html post using JQuery. I am using .net version 4.0 and cannot upgrade to 4.5 in the actual solution. So I had to install the Microsoft.Net.Http using nuget cmd

    PM> install-package Microsoft.Net.Http
    
    Private Function UploadFile(req As ApiRequest, filePath As String, fileName As String) As String
        Dim result = String.empty
        Try
            ''//Get file stream
            Dim paramFileStream As Stream = File.OpenRead(filePath)
            Dim fileStreamContent As HttpContent = New  StreamContent(paramFileStream)
            Using client = New HttpClient()
                Using formData = New MultipartFormDataContent()
                    ''// This adds parameter name ("action")
                    ''// parameter value (req.Action) to form data
                    formData.Add(New StringContent(req.Action), "action")
                    formData.Add(New StringContent(req.ApiKey), "apiKey")
                    For Each param In req.Parameters
                        formData.Add(New StringContent(param.Value), param.Key)
                    Next
                    formData.Add(New StringContent(req.getRequestSignature.Qualifier), "signature")
                    ''//This adds the file stream and file info to form data
                    formData.Add(fileStreamContent, "file", fileName)
                    ''//We are now sending the request
                    Dim response = client.PostAsync(GetAPIEndpoint(), formData).Result
                    ''//We are here reading the response
                    Dim readR = New StreamReader(response.Content.ReadAsStreamAsync().Result, Encoding.UTF8)
                    Dim respContent = readR.ReadToEnd()
    
                    If Not response.IsSuccessStatusCode Then
                        result =  "Request Failed : Code = " & response.StatusCode & "Reason = " & response.ReasonPhrase & "Message = " & respContent
                    End If
                    result.Value = respContent
                End Using
            End Using
        Catch ex As Exception
            result = "An error occurred : " & ex.Message
        End Try
    
        Return result
    End Function
    
    0 讨论(0)
提交回复
热议问题