是否有任何类,库或一些代码片段,将帮助我上传文件与HTTPWebrequest?

编辑2:

我不想上传到WebDAV文件夹或类似的东西。我想模拟一个浏览器,就像你上传你的头像到一个论坛或通过一个web应用程序中的表单上传一个文件。上传到一个使用multipart/form-data的表单。

编辑:

WebClient不覆盖我的需求,所以我正在寻找一个解决方案与HTTPWebrequest。


当前回答

我的ASP。NET上传常见问题解答中有一篇关于这方面的文章,有示例代码:使用HttpWebRequest/WebClient的RFC 1867 POST请求上传文件。此代码不将文件加载到内存中(与上面的代码相反),支持多个文件,并支持表单值、设置凭据和cookie等。

编辑:看起来好像是Axosoft把这个页面删除了。谢谢你的家伙。

它仍然可以通过archive.org访问。

其他回答

VB示例(从另一篇文章中的c#示例转换而来):

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

修改了@CristianRomanescu代码,以使用内存流,接受文件作为字节数组,允许空nvc,返回请求响应和使用授权头。使用Web Api 2测试代码。

private string HttpUploadFile(string url, byte[] file, string fileName, string paramName, string contentType, NameValueCollection nvc, string authorizationHeader)
{
    string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
    byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

    HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
    wr.ContentType = "multipart/form-data; boundary=" + boundary;
    wr.Method = "POST";
    wr.Headers.Add("Authorization", authorizationHeader);
    wr.KeepAlive = true;

    Stream rs = wr.GetRequestStream();

    string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
    if (nvc != null)
    {
        foreach (string key in nvc.Keys)
        {
            rs.Write(boundarybytes, 0, boundarybytes.Length);
            string formitem = string.Format(formdataTemplate, key, nvc[key]);
            byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
            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, paramName, fileName, contentType);
    byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
    rs.Write(headerbytes, 0, headerbytes.Length);

    rs.Write(file, 0, file.Length);

    byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
    rs.Write(trailer, 0, trailer.Length);
    rs.Close();

    WebResponse wresp = null;
    try
    {
        wresp = wr.GetResponse();
        Stream stream2 = wresp.GetResponseStream();
        StreamReader reader2 = new StreamReader(stream2);
        var response = reader2.ReadToEnd();
        return response;
    }
    catch (Exception ex)
    {
        if (wresp != null)
        {
            wresp.Close();
            wresp = null;
        }
        return null;
    }
    finally
    {
        wr = null;
    }
}

Testcode:

[HttpPost]
[Route("postformdata")]
public IHttpActionResult PostFormData()
{
    // Check if the request contains multipart/form-data.
    if (!Request.Content.IsMimeMultipartContent())
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    var provider = new MultipartMemoryStreamProvider();

    try
    {
        // Read the form data.
        var result = Request.Content.ReadAsMultipartAsync(provider).Result;
        string response = "";
        // This illustrates how to get the file names.
        foreach (var file in provider.Contents)
        {
            var fileName = file.Headers.ContentDisposition.FileName.Trim('\"');
            var buffer =  file.ReadAsByteArrayAsync().Result;
            response = HttpUploadFile("https://localhost/api/v1/createfromfile", buffer, fileName, "file", "application/pdf", null, "AuthorizationKey");
        }
        return Ok(response);
    }
    catch (System.Exception e)
    {
        return InternalServerError();
    }
}

查看MyToolkit库:

var request = new HttpPostRequest("http://www.server.com");
request.Data.Add("name", "value"); // POST data
request.Files.Add(new HttpPostFile("name", "file.jpg", "path/to/file.jpg")); 

await Http.PostAsync(request, OnRequestFinished);

http://mytoolkit.codeplex.com/wikipage?title=Http

我想在VB中做文件上传和添加一些参数到multipart/form-data请求。NET而不是通过正规的表单发布。 感谢@JoshCodes的回答,我找到了我一直在寻找的方向。 我发布我的解决方案是为了帮助其他人找到一种方法来使用文件和参数来执行帖子 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

对于我来说,下面的作品(主要是受到以下所有回答的启发),我从Elad的回答开始,修改/简化事情以符合我的需要(删除不是文件形式输入,只有一个文件,……)

希望它能帮助到一些人:)

(PS:我知道异常处理没有实现,并且假设它是在一个类中编写的,所以我可能需要一些集成工作…)

private void uploadFile()
    {
        Random rand = new Random();
        string boundary = "----boundary" + rand.Next().ToString();
        Stream data_stream;
        byte[] header = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"file_path\"; filename=\"" + System.IO.Path.GetFileName(this.file) + "\"\r\nContent-Type: application/octet-stream\r\n\r\n");
        byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");

        // Do the request
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(MBF_URL);
        request.UserAgent = "My Toolbox";
        request.Method = "POST";
        request.KeepAlive = true;
        request.ContentType = "multipart/form-data; boundary=" + boundary;
        data_stream = request.GetRequestStream();
        data_stream.Write(header, 0, header.Length);
        byte[] file_bytes = System.IO.File.ReadAllBytes(this.file);
        data_stream.Write(file_bytes, 0, file_bytes.Length);
        data_stream.Write(trailer, 0, trailer.Length);
        data_stream.Close();

        // Read the response
        WebResponse response = request.GetResponse();
        data_stream = response.GetResponseStream();
        StreamReader reader = new StreamReader(data_stream);
        this.url = reader.ReadToEnd();

        if (this.url == "") { this.url = "No response :("; }

        reader.Close();
        data_stream.Close();
        response.Close();
    }