首页 / C#开发 / 正文

[C#].NET/C#编程的应用程序开发中如何使用HttpWebRequest(multipart/form-data)上传文件呢?

3812 1 发布于: 2018-05-17 读完约需30分钟

问题描述

在.NET/C#编程的应用程序开发中,如何使用HttpWebRequest(multipart/form-data)上传文件呢?很多人会想到使用WebClient类来处理这个问题,但除了WebClient类外,还有其他的实现方式呢?使用HttpWebRequest又应该如何实现C#文件的上传功能呢?

方案一

此方案使用HttpWebRequest实现了文件(支持多个文件)上传的功能,如下:

public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc) {
        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.KeepAlive = true;
        wr.Credentials = System.Net.CredentialCache.DefaultCredentials;

        Stream rs = wr.GetRequestStream();

        string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
        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, file, contentType);
        byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
        rs.Write(headerbytes, 0, headerbytes.Length);

        FileStream fileStream = new FileStream(file, 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);
        } catch(Exception ex) {
            if(wresp != null) {
                wresp.Close();
                wresp = null;
            }
        } finally {
            wr = null;
        }
    }

调用示例:

NameValueCollection nvc = new NameValueCollection();
    nvc.Add("id", "TTR");
    nvc.Add("btn-submit-photo", "Upload");
    HttpUploadFile("http://your.server.com/upload", 
         @"C:\test\test.jpg", "file", "image/jpeg", nvc);

方案二

使用HttpWebRequest实现的另一个封装方法,如下:

public static string UploadFilesToRemoteUrl(string url, string[] files, NameValueCollection formFields = null)
{
    string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");

    HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
    request.ContentType = "multipart/form-data; boundary=" +
                            boundary;
    request.Method = "POST";
    request.KeepAlive = true;

    Stream memStream = new System.IO.MemoryStream();

    var boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
                                                            boundary + "\r\n");
    var endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
                                                                boundary + "--");


    string formdataTemplate = "\r\n--" + boundary +
                                "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";

    if (formFields != null)
    {
        foreach (string key in formFields.Keys)
        {
            string formitem = string.Format(formdataTemplate, key, formFields[key]);
            byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
            memStream.Write(formitembytes, 0, formitembytes.Length);
        }
    }

    string headerTemplate =
        "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
        "Content-Type: application/octet-stream\r\n\r\n";

    for (int i = 0; i < files.Length; i++)
    {
        memStream.Write(boundarybytes, 0, boundarybytes.Length);
        var header = string.Format(headerTemplate, "uplTheFile", files[i]);
        var headerbytes = System.Text.Encoding.UTF8.GetBytes(header);

        memStream.Write(headerbytes, 0, headerbytes.Length);

        using (var fileStream = new FileStream(files[i], FileMode.Open, FileAccess.Read))
        {
            var buffer = new byte[1024];
            var bytesRead = 0;
            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
            {
                memStream.Write(buffer, 0, bytesRead);
            }
        }
    }

    memStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
    request.ContentLength = memStream.Length;

    using (Stream requestStream = request.GetRequestStream())
    {
        memStream.Position = 0;
        byte[] tempBuffer = new byte[memStream.Length];
        memStream.Read(tempBuffer, 0, tempBuffer.Length);
        memStream.Close();
        requestStream.Write(tempBuffer, 0, tempBuffer.Length);
    }

    using (var response = request.GetResponse())
    {
        Stream stream2 = response.GetResponseStream();
        StreamReader reader2 = new StreamReader(stream2);
        return reader2.ReadToEnd();
    }
}

方案三

在.NET Framework 4.5及以上版本中(如果你是.NET Framework 4.0版本,可以通过使用NuGet包管理工具添加Microsoft.Net.Http组件的引用),可以使用HttpClient类来实现文件上传的功能,而且编码更简单,快捷。封装的.NET/C#文件上传方法如下:

public System.IO.Stream Upload(string url, string filename, Stream fileStream, byte [] fileBytes)

    HttpContent stringContent = new StringContent(filename);
    HttpContent fileStreamContent = new StreamContent(fileStream);
    HttpContent bytesContent = new ByteArrayContent(fileBytes);

    using (var client = new HttpClient())
    using (var formData = new MultipartFormDataContent()) 
    {
        formData.Add(stringContent, "filename", "filename");
        formData.Add(fileStreamContent, "file1", "file1");
        formData.Add(bytesContent, "file2", "file2");

        var response = client.PostAsync(url, formData).Result;

        if (!response.IsSuccessStatusCode)
        {
            return null;
        }
        return response.Content.ReadAsStreamAsync().Result;
    }
}

方案四

此方案封装了一个支持多文件上传和支持文件流(不需要本地文件)的C#文件上传方法,如下:

public class FormFile 
{
    public string Name { get; set; }

    public string ContentType { get; set; }

    public string FilePath { get; set; }

    public Stream Stream { get; set; }
}

public class RequestHelper
{

    public static string PostMultipart(string url, Dictionary<string, object> parameters) {

        string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
        byte[] boundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.ContentType = "multipart/form-data; boundary=" + boundary;
        request.Method = "POST";
        request.KeepAlive = true;
        request.Credentials = System.Net.CredentialCache.DefaultCredentials;

        if(parameters != null && parameters.Count > 0) {

            using(Stream requestStream = request.GetRequestStream()) {

                foreach(KeyValuePair<string, object> pair in parameters) {

                    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                    if(pair.Value is FormFile) {
                        FormFile file = pair.Value as FormFile;
                        string header = "Content-Disposition: form-data; name=\"" + pair.Key + "\"; filename=\"" + file.Name + "\"\r\nContent-Type: " + file.ContentType + "\r\n\r\n";
                        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(header);
                        requestStream.Write(bytes, 0, bytes.Length);
                        byte[] buffer = new byte[32768];
                        int bytesRead;
                        if(file.Stream == null) {
                            // 从本地文件上传
                            using(FileStream fileStream = File.OpenRead(file.FilePath)) {
                                while((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                                    requestStream.Write(buffer, 0, bytesRead);
                                fileStream.Close();
                            }
                        }
                        else {
                            // 从文件流上传
                            while((bytesRead = file.Stream.Read(buffer, 0, buffer.Length)) != 0)
                                requestStream.Write(buffer, 0, bytesRead);
                        }
                    }
                    else {
                        string data = "Content-Disposition: form-data; name=\"" + pair.Key + "\"\r\n\r\n" + pair.Value;
                        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
                        requestStream.Write(bytes, 0, bytes.Length);
                    }
                }

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

        using(WebResponse response = request.GetResponse()) {
            using(Stream responseStream = response.GetResponseStream())
            using(StreamReader reader = new StreamReader(responseStream))
                return reader.ReadToEnd();
        }
    }
}

调用示例:

RequestHelper.PostMultipart(
    "http://www.myserver.com/upload.php", 
    new Dictionary<string, object>() {
        { "testparam", "my value" },
        { "file", new FormFile() { Name = "image.jpg", ContentType = "image/jpeg", FilePath = "c:\\temp\\myniceimage.jpg" } },
        { "other_file", new FormFile() { Name = "image2.jpg", ContentType = "image/jpeg", Stream = imageDataStream } },
    });

版权声明:本作品系原创,版权归码友网所有,如未经许可,禁止任何形式转载,违者必究。

上一篇: [C#].NET/C#编程的应用程序开发中读取大文件并将其转换成字节数组(byte array)的方式有哪些,哪种更好呢?

下一篇: [C#].NET/C#应用程序开发中如何在控制器(Controller)中获取ASP.NET MVC WEB 应用程序的绝对路径?

本文永久链接码友网 » [C#].NET/C#编程的应用程序开发中如何使用HttpWebRequest(multipart/form-data)上传文件呢?

分享扩散:

发表评论

登录用户才能发表评论, 请 登 录 或者 注册