[C#]使用WebClient上传文件并同时Post表单数据字段到服务端


    之前遇到一个问题,就是使用WebClient上传文件的同时,还要Post表单数据字段,一开始以为WebClient可以直接做到,结果发现如果先Post表单字段,就只能获取到字段及其值,如果先上传文件,也只能获取到上传文件的内容。测试了不少时间才发现WebClient不能这么使用。

    Google到相关的解决思路和类,因为发现网上的一些文章不是介绍得太简单就是太复杂,所以这里简单整理一下,既能帮助自己巩固知识,也希望能够帮到大家!如果大家有什么不明白,可以直接留言问我。

    关于WebClient上传文件并同时Post表单数据的实现原理,大家可以参考这篇文章http://www.cnblogs.com/goody9807/archive/2007/06/06/773735.html,介绍得非常详细,但是类和实例有些模糊,所以类和实例可以直接参考本文。

HttpRequestClient类Code:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Net;

namespace Common.Helper
{
  /// <summary>
  /// description:http post请求客户端
  /// last-modified-date:2012-02-28
  /// </summary>
  public class HttpRequestClient
  {
    #region //字段
    private ArrayList bytesArray;
    private Encoding encoding = Encoding.UTF8;
    private string boundary = String.Empty;
    #endregion

    #region //构造方法
    public HttpRequestClient()
    {
      bytesArray = new ArrayList();
      string flag = DateTime.Now.Ticks.ToString("x");
      boundary = "---------------------------" + flag;
    }
    #endregion

    #region //方法
    /// <summary>
    /// 合并请求数据
    /// </summary>
    /// <returns></returns>
    private byte[] MergeContent()
    {
      int length = 0;
      int readLength = 0;
      string endBoundary = "--" + boundary + "--\r\n";
      byte[] endBoundaryBytes = encoding.GetBytes(endBoundary);

      bytesArray.Add(endBoundaryBytes);

      foreach (byte[] b in bytesArray)
      {
        length += b.Length;
      }

      byte[] bytes = new byte[length];

      foreach (byte[] b in bytesArray)
      {
        b.CopyTo(bytes, readLength);
        readLength += b.Length;
      }

      return bytes;
    }

    /// <summary>
    /// 上传
    /// </summary>
    /// <param name="requestUrl">请求url</param>
    /// <param name="responseText">响应</param>
    /// <returns></returns>
    public bool Upload(String requestUrl, out String responseText)
    {
      WebClient webClient = new WebClient();
      webClient.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);

      byte[] responseBytes;
      byte[] bytes = MergeContent();

      try
      {
        responseBytes = webClient.UploadData(requestUrl, bytes);
        responseText = System.Text.Encoding.UTF8.GetString(responseBytes);
        return true;
      }
      catch (WebException ex)
      {
        Stream responseStream = ex.Response.GetResponseStream();
        responseBytes = new byte[ex.Response.ContentLength];
        responseStream.Read(responseBytes, 0, responseBytes.Length);
      }
      responseText = System.Text.Encoding.UTF8.GetString(responseBytes);
      return false;
    }

    /// <summary>
    /// 设置表单数据字段
    /// </summary>
    /// <param name="fieldName">字段名</param>
    /// <param name="fieldValue">字段值</param>
    /// <returns></returns>
    public void SetFieldValue(String fieldName, String fieldValue)
    {
      string httpRow = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}\r\n";
      string httpRowData = String.Format(httpRow, fieldName, fieldValue);

      bytesArray.Add(encoding.GetBytes(httpRowData));
    }

    /// <summary>
    /// 设置表单文件数据
    /// </summary>
    /// <param name="fieldName">字段名</param>
    /// <param name="filename">字段值</param>
    /// <param name="contentType">内容内型</param>
    /// <param name="fileBytes">文件字节流</param>
    /// <returns></returns>
    public void SetFieldValue(String fieldName, String filename, String contentType, Byte[] fileBytes)
    {
      string end = "\r\n";
      string httpRow = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
      string httpRowData = String.Format(httpRow, fieldName, filename, contentType);

      byte[] headerBytes = encoding.GetBytes(httpRowData);
      byte[] endBytes = encoding.GetBytes(end);
      byte[] fileDataBytes = new byte[headerBytes.Length + fileBytes.Length + endBytes.Length];

      headerBytes.CopyTo(fileDataBytes, 0);
      fileBytes.CopyTo(fileDataBytes, headerBytes.Length);
      endBytes.CopyTo(fileDataBytes, headerBytes.Length + fileBytes.Length);

      bytesArray.Add(fileDataBytes);
    }
    #endregion
  }
}

客户端实例代码:

string fileFullName=@"c:\test.txt",filedValue="hello_world",responseText = "";
FileStream fs = new FileStream(fileFullName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
byte[] fileBytes = new byte[fs.Length];
fs.Read(fileBytes, 0, fileBytes.Length);
fs.Close(); fs.Dispose();

HttpRequestClient httpRequestClient = new HttpRequestClient();
httpRequestClient.SetFieldValue("key", filedValue);
httpRequestClient.SetFieldValue("uploadfile", Path.GetFileName(fileFullName), "application/octet-stream", fileBytes);
httpRequestClient.Upload(NormalBotConfig.Instance.GetUploadFileUrl(), out responseText);

服务端实例代码:

      if (HttpContext.Current.Request.Files.AllKeys.Length > 0)
      {
        string filePath = Path.Combine(HttpContext.Current.Server.MapPath("~/"), "UploadFile", DateTime.Now.Year.ToString(), DateTime.Now.Month.ToString(), DateTime.Now.Day.ToString());
        if (!Directory.Exists(filePath)) Directory.CreateDirectory(filePath);
        //这里我直接用索引来获取第一个文件,如果上传了多个文件,可以通过遍历HttpContext.Current.Request.Files.AllKeys取“key值”,再通过HttpContext.Current.Request.Files[“key值”]获取文件
        HttpContext.Current.Request.Files[0].SaveAs(Path.Combine(filePath, HttpContext.Current.Request.Files[0].FileName));
        string filedValue = HttpContext.Current.Request.Form["key"];
      }

,

有 2 条《[C#]使用WebClient上传文件并同时Post表单数据字段到服务端》的回复

  1. 是什么蛋疼的服务端要同时上传文件和post表单。。。

发表评论

3 + 8 = ?