使用WebBrowser实例从C#-WinForm上传带有POST的文件

本文关键字:POST 文件 WebBrowser 实例 C#-WinForm 使用 | 更新日期: 2023-09-27 17:59:01

我想用.net 2.0从浏览器窗口(或WebBrowser实例)中的C#WinForm应用程序对PHP站点进行POST,我需要正确地获取数据和标头参数。类似:

webBrowser1.Navigate("http://mypublishservice.com/publish_picture.php","_SELF",X,Y); 

问题是:X和Y应该是什么?我知道必须在byte[]数组中填充所有标头和文件数据,并添加一些额外的标头作为字符串。我在下面做了网络表单的例子,并用firebug进行了检查。所以我知道POST数据应该是什么样子。我甚至创建了一个HttpWebRequest,这还可以,但我需要一个WebBrowser(原因如下)来启动Post Request。所以我迷路了。我尝试了很多选项,例如使用HTTPWebrequest上传文件(多部分/表单数据)。也许还有更好的方法,创建一个HttpWeb请求,然后将其传递给WebBrowser实例或类似的东西?

下面是一个调用publish_picture.php页面的web表单,该页面运行良好:

<!DOCTYPE html>
<html>
  <head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <div>
      <form enctype="multipart/form-data" action="http://mypublishservice.com/publish_picture.php" method="POST">
      Please choose a photo:
      <input name="source" type="file"><br/><br/>
      Say something about this photo:
      <input name="message" type="text" value=""><br/><br/>
      <input type="submit" value="Upload"/><br/>
      </form>
    </div>
  </body>
</html>

如果你问我为什么要这样做,这里有一些想法来为我愚蠢的决定辩护;)

为什么是WebBrowser实例而不是简单的HttpWebrequest?因为目标服务(例如Facebook)需要(或似乎需要)一个合适的浏览器!为什么不使用目标服务API(例如Facebook API)?发现,桌面Web通信不好(400个错误太多)。

更新2:

看起来好多了。尽管如此,我还是得到了一个错误,但它可能是PHP页面本身。这就是你的想法吗?

   public static byte[] PrepareUploadFiles(string address, IEnumerable<UploadFile> files, NameValueCollection values, out string header)
   {
       using (var requestStream = new MemoryStream())
       {
           var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); //, NumberFormatInfo.InvariantInfo);
           header = "multipart/form-data; boundary=" + boundary;
           var boundaryBuffer2 = Encoding.ASCII.GetBytes(header);
               requestStream.Write(boundaryBuffer2, 0, boundaryBuffer2.Length);
               boundary = "--" + boundary;
               // Write the values
               foreach (string name in values.Keys)
           {
               var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
               requestStream.Write(buffer, 0, buffer.Length);
               buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name='"{0}'"{1}{1}", name, Environment.NewLine));
               requestStream.Write(buffer, 0, buffer.Length);
               buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
               requestStream.Write(buffer, 0, buffer.Length);
           }
           // Write the files
           foreach (var file in files)
           {
               var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
               requestStream.Write(buffer, 0, buffer.Length);
               buffer = Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name='"{0}'"; filename='"{1}'"{2}", file.Name, file.Filename, Environment.NewLine));
               requestStream.Write(buffer, 0, buffer.Length);
               buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", file.ContentType, Environment.NewLine));
               requestStream.Write(buffer, 0, buffer.Length);
               CopyStream(file.Stream, requestStream); // file.Stream.CopyTo(requestStream);
               buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
               requestStream.Write(buffer, 0, buffer.Length);
           }
           var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--");
           requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length);
           return requestStream.ToArray(); 
       }
   }
   public static void CopyStream(Stream input, Stream output)
   {
       byte[] buffer = new byte[32768];
       while (true)
       {
           int read = input.Read(buffer, 0, buffer.Length);
           if (read <= 0)
               return;
           output.Write(buffer, 0, read);
       }
 }

public void Upload()
{
  using (var stream1 = File.Open(Support.EXAMPLEIMAGE, FileMode.Open))
        {
            var files = new[] 
                 {
                new UploadFile
               {
            Name = "source",  // 1
            Filename = Support.EXAMPLEIMAGE,
            ContentType = "image/jpeg",   // 2
            Stream = stream1
              }
          };
          var values = new NameValueCollection
        {
         { "message", "a text" }   // 3
         };

             string contentType;  // 4. do I need it  
            byte[] dataToPost = Support.PrepareUploadFiles(Support.URL, files, values, out contentType); // 5. out contentType = what should be the result vaule?
            //PrepareUploadFiles(url, files, values, out contentType);
            webBrowser1.Navigate(Support.URL, null, dataToPost, "Content-Type: " + contentType + Environment.NewLine); 
        }

    }

使用WebBrowser实例从C#-WinForm上传带有POST的文件

我个人喜欢使用ParseQueryString方法,因为它可以正确编码参数:

var values = HttpUtility.ParseQueryString(string.Empty);
values["param1"] = "param1 value";
values["param2"] = "param2 value";
values["param3"] = "param3 value";
var dataToPost = Encoding.UTF8.GetBytes(values.ToString());
var url = "http://mypublishservice.com/publish_picture.php";
var contentType = "Content-Type: application/x-www-form-urlencoded" + Environment.NewLine;
webBrowser1.Navigate(url, null, dataToPost, contentType); 

现在,因为你正在尝试上传文件,这会有点困难。我写了一篇博客文章,介绍了如何生成允许上传多个文件的multipart/form-data请求。因此,您可以调整上面显示的UploadFiles方法,只返回POST主体,而不进行实际上传,然后:

string contentType;
byte[] dataToPost = PrepareUploadFiles(url, files, values, out contentType);
webBrowser1.Navigate(url, null, dataToPost, "Content-Type: " + contentType + Environment.NewLine);