使用 WebBrowser-Instance 从 C#-WinForm 上传文件?

发布于 2024-11-15 13:38:05 字数 5214 浏览 3 评论 0原文

我想使用 .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 (multipart/form-data) 上传文件。也许有更好的方法,通过创建 HttpWebrequest 并将其传递给 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); 
        }


    }

I want to make a POST to a PHP site from a C# WinForm Application in a Browser window (or a WebBrowser-instance) with .net 2.0 and I need to get the data and the headers-argments right. Like:

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

The question is: What should be X and Y? I know a have to fill all headers and file data in a byte[] array and add some additional headers as strings. I made examples of the webform below and examined them with firebug. So i know how the POST data should look like. I even created a HttpWebRequest which was ok, but I need a WebBrowser (reasons below) to start the Post-Request. So i am lost. I have tried many options, e.g. Upload files with HTTPWebrequest (multipart/form-data). Maybe there is a better way, by creating a HttpWebrequest and than passing this to a WebBrowser-instance or something like that?

Here is a web form to call the publish_picture.php page that works fine:

<!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>

In case you ask why I want to do it THIS way, here some thoughts to defend my silly decision ;)

Why a WebBrowser-instance and not a simple HttpWebrequest? Because the target service (e.g. Facebook) needs (or seems to need) a proper Browser!
Why not the target service APIs (e.g. Facebook API)? Found out, that Desktop-Web-communication is not good (too many 400-Errors).

UPDATE 2:

Looks better. Still I get an error but it might be the PHP page itself. Is this what you have in mind?

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


    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

哆啦不做梦 2024-11-22 13:38:05

就我个人而言,我喜欢使用 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); 

Personally I like using the ParseQueryString method as it takes care of properly encoding parameters:

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); 

Now, because you are trying to upload files this is going to be a little more difficult. I wrote a blog post which illustrates how to generate a multipart/form-data request allowing to upload multiple files. So you could tweak the UploadFiles method shown there to only return the POST body and not do the actual upload and then:

string contentType;
byte[] dataToPost = PrepareUploadFiles(url, files, values, out contentType);
webBrowser1.Navigate(url, null, dataToPost, "Content-Type: " + contentType + Environment.NewLine); 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文