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

编辑2:

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

编辑:

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


当前回答

修改了@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();
    }
}

其他回答

该方法适用于同时上传多张图片

        var flagResult = new viewModel();
        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 = method;
        wr.KeepAlive = true;
        wr.Credentials = System.Net.CredentialCache.DefaultCredentials;

        Stream rs = wr.GetRequestStream();


        string path = @filePath;
        System.IO.DirectoryInfo folderInfo = new DirectoryInfo(path);

        foreach (FileInfo file in folderInfo.GetFiles())
        {
            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, file, contentType);
            byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
            rs.Write(headerbytes, 0, headerbytes.Length);

            FileStream fileStream = new FileStream(file.FullName, 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();

        WebResponse wresp = null;
        try
        {
            wresp = wr.GetResponse();
            Stream stream2 = wresp.GetResponseStream();
            StreamReader reader2 = new StreamReader(stream2);
            var result = reader2.ReadToEnd();
            var cList = JsonConvert.DeserializeObject<HttpViewModel>(result);
            if (cList.message=="images uploaded!")
            {
                flagResult.success = true;
            }

        }
        catch (Exception ex)
        {
            //log.Error("Error uploading file", ex);
            if (wresp != null)
            {
                wresp.Close();
                wresp = null;
            }
        }
        finally
        {
            wr = null;
        }
        return flagResult;
    }

我最近不得不处理这个问题——另一种方法是使用WebClient是可继承的这一事实,并从那里改变底层的WebRequest:

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

我更喜欢c#,但如果你坚持使用VB,结果将是这样的:

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

这不需要外部代码、扩展和“低级”HTTP操作(只需要NuGet中的Microsoft.Net.Http包)。这里有一个例子:

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

客户端使用转换文件到ToBase64String,使用Xml发布后 到服务器调用,这个服务器使用File.WriteAllBytes(path,Convert.FromBase64String(dataFile_Client_sent))。

好幸运!

我写了一个类使用WebClient方式做多部分的表单上传。

http://ferozedaud.blogspot.com/2010/03/multipart-form-upload-helper.html

/// 
/// MimePart
/// Abstract class for all MimeParts
/// 

abstract class MimePart
{
    public string Name { get; set; }

    public abstract string ContentDisposition { get; }

    public abstract string ContentType { get; }

    public abstract void CopyTo(Stream stream);

    public String Boundary
    {
        get;
        set;
    }
}

class NameValuePart : MimePart
{
    private NameValueCollection nameValues;

    public NameValuePart(NameValueCollection nameValues)
    {
        this.nameValues = nameValues;
    }

    public override void CopyTo(Stream stream)
    {
        string boundary = this.Boundary;
        StringBuilder sb = new StringBuilder();

        foreach (object element in this.nameValues.Keys)
        {
            sb.AppendFormat("--{0}", boundary);
            sb.Append("\r\n");
            sb.AppendFormat("Content-Disposition: form-data; name=\"{0}\";", element);
            sb.Append("\r\n");
            sb.Append("\r\n");
            sb.Append(this.nameValues[element.ToString()]);

            sb.Append("\r\n");

        }

        sb.AppendFormat("--{0}", boundary);
        sb.Append("\r\n");

        //Trace.WriteLine(sb.ToString());
        byte [] data = Encoding.ASCII.GetBytes(sb.ToString());
        stream.Write(data, 0, data.Length);
    }

    public override string ContentDisposition
    {
        get { return "form-data"; }
    }

    public override string ContentType
    {
        get { return String.Empty; }
    }
} 

class FilePart : MimePart

{

    private Stream input;

    private String contentType;



    public FilePart(Stream input, String name, String contentType)

    {

        this.input = input;

        this.contentType = contentType;

        this.Name = name;

    }



    public override void CopyTo(Stream stream)

    {

        StringBuilder sb = new StringBuilder();

        sb.AppendFormat("Content-Disposition: {0}", this.ContentDisposition);

        if (this.Name != null)

            sb.Append("; ").AppendFormat("name=\"{0}\"", this.Name);

        if (this.FileName != null)

            sb.Append("; ").AppendFormat("filename=\"{0}\"", this.FileName);

        sb.Append("\r\n");

        sb.AppendFormat(this.ContentType);

        sb.Append("\r\n");

        sb.Append("\r\n");



    // serialize the header data.

    byte[] buffer = Encoding.ASCII.GetBytes(sb.ToString());

    stream.Write(buffer, 0, buffer.Length);



    // send the stream.

    byte[] readBuffer = new byte[1024];

    int read = input.Read(readBuffer, 0, readBuffer.Length);

    while (read > 0)

    {

        stream.Write(readBuffer, 0, read);

        read = input.Read(readBuffer, 0, readBuffer.Length);

    }



    // write the terminating boundary

    sb.Length = 0;

    sb.Append("\r\n");

    sb.AppendFormat("--{0}", this.Boundary);

    sb.Append("\r\n");

    buffer = Encoding.ASCII.GetBytes(sb.ToString());

    stream.Write(buffer, 0, buffer.Length);



}

 public override string ContentDisposition
 {
      get { return "file"; }
 }



 public override string ContentType
 {
    get { 
       return String.Format("content-type: {0}", this.contentType); 
     }
 }

 public String FileName { get; set; }

}

    /// 
    /// Helper class that encapsulates all file uploads
    /// in a mime part.
    /// 

    class FilesCollection : MimePart
    {
        private List files;

        public FilesCollection()
        {
            this.files = new List();
            this.Boundary = MultipartHelper.GetBoundary();
        }

        public int Count
        {
            get { return this.files.Count; }
        }

        public override string ContentDisposition
        {
            get
            {
                return String.Format("form-data; name=\"{0}\"", this.Name);
            }
        }

        public override string ContentType
        {
            get { return String.Format("multipart/mixed; boundary={0}", this.Boundary); }
        }

        public override void CopyTo(Stream stream)
        {
            // serialize the headers
            StringBuilder sb = new StringBuilder(128);
            sb.Append("Content-Disposition: ").Append(this.ContentDisposition).Append("\r\n");
            sb.Append("Content-Type: ").Append(this.ContentType).Append("\r\n");
            sb.Append("\r\n");
            sb.AppendFormat("--{0}", this.Boundary).Append("\r\n");

            byte[] headerBytes = Encoding.ASCII.GetBytes(sb.ToString());
            stream.Write(headerBytes, 0, headerBytes.Length);
            foreach (FilePart part in files)
            {
                part.Boundary = this.Boundary;
                part.CopyTo(stream);
            }
        }

        public void Add(FilePart part)
        {
            this.files.Add(part);
        }
    }

/// 
/// Helper class to aid in uploading multipart
/// entities to HTTP web endpoints.
/// 

class MultipartHelper
{
    private static Random random = new Random(Environment.TickCount);

    private List formData = new List();
    private FilesCollection files = null;
    private MemoryStream bufferStream = new MemoryStream();
    private string boundary;

    public String Boundary { get { return boundary; } }

    public static String GetBoundary()
    {
        return Environment.TickCount.ToString("X");
    }

    public MultipartHelper()
    {
        this.boundary = MultipartHelper.GetBoundary();
    }

    public void Add(NameValuePart part)
    {
        this.formData.Add(part);
        part.Boundary = boundary;
    }

    public void Add(FilePart part)
    {
        if (files == null)
        {
            files = new FilesCollection();
        }
        this.files.Add(part);
    }

    public void Upload(WebClient client, string address, string method)
    {
        // set header
        client.Headers.Add(HttpRequestHeader.ContentType, "multipart/form-data; boundary=" + this.boundary);
        Trace.WriteLine("Content-Type: multipart/form-data; boundary=" + this.boundary + "\r\n");

        // first, serialize the form data
        foreach (NameValuePart part in this.formData)
        {
            part.CopyTo(bufferStream);
        }

        // serialize the files.
        this.files.CopyTo(bufferStream);

        if (this.files.Count > 0)
        {
            // add the terminating boundary.
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("--{0}", this.Boundary).Append("\r\n");
            byte [] buffer = Encoding.ASCII.GetBytes(sb.ToString());
            bufferStream.Write(buffer, 0, buffer.Length);
        }

        bufferStream.Seek(0, SeekOrigin.Begin);

        Trace.WriteLine(Encoding.ASCII.GetString(bufferStream.ToArray()));
        byte [] response = client.UploadData(address, method, bufferStream.ToArray());
        Trace.WriteLine("----- RESPONSE ------");
        Trace.WriteLine(Encoding.ASCII.GetString(response));
    }

    /// 
    /// Helper class that encapsulates all file uploads
    /// in a mime part.
    /// 

    class FilesCollection : MimePart
    {
        private List files;

        public FilesCollection()
        {
            this.files = new List();
            this.Boundary = MultipartHelper.GetBoundary();
        }

        public int Count
        {
            get { return this.files.Count; }
        }

        public override string ContentDisposition
        {
            get
            {
                return String.Format("form-data; name=\"{0}\"", this.Name);
            }
        }

        public override string ContentType
        {
            get { return String.Format("multipart/mixed; boundary={0}", this.Boundary); }
        }

        public override void CopyTo(Stream stream)
        {
            // serialize the headers
            StringBuilder sb = new StringBuilder(128);
            sb.Append("Content-Disposition: ").Append(this.ContentDisposition).Append("\r\n");
            sb.Append("Content-Type: ").Append(this.ContentType).Append("\r\n");
            sb.Append("\r\n");
            sb.AppendFormat("--{0}", this.Boundary).Append("\r\n");

            byte[] headerBytes = Encoding.ASCII.GetBytes(sb.ToString());
            stream.Write(headerBytes, 0, headerBytes.Length);
            foreach (FilePart part in files)
            {
                part.Boundary = this.Boundary;
                part.CopyTo(stream);
            }
        }

        public void Add(FilePart part)
        {
            this.files.Add(part);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        Trace.Listeners.Add(new ConsoleTraceListener());
        try
        {
            using (StreamWriter sw = new StreamWriter("testfile.txt", false))
            {
                sw.Write("Hello there!");
            }

            using (Stream iniStream = File.OpenRead(@"c:\platform.ini"))
            using (Stream fileStream = File.OpenRead("testfile.txt"))
            using (WebClient client = new WebClient())
            {
                MultipartHelper helper = new MultipartHelper();

                NameValueCollection props = new NameValueCollection();
                props.Add("fname", "john");
                props.Add("id", "acme");
                helper.Add(new NameValuePart(props));

                FilePart filepart = new FilePart(fileStream, "pics1", "text/plain");
                filepart.FileName = "1.jpg";
                helper.Add(filepart);

                FilePart ini = new FilePart(iniStream, "pics2", "text/plain");
                ini.FileName = "inifile.ini";
                helper.Add(ini);

                helper.Upload(client, "http://localhost/form.aspx", "POST");
            }
        }
        catch (Exception e)
        {
            Trace.WriteLine(e);
        }
    }
}

这将适用于所有版本的. net框架。