|
||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionI needed to attach files silently to HTML forms hosted in a As you probably know, for security reasons, it is not possible to change the value of the HTML form file input programmatically. My first approach was to set focus on the input field and then do some After examining the methods of the WebBrowser.Navigate(Uri url, string targetFrameName,
byte[] postData, string additionalHeaders)
There is a good example of how to make correct multipart request headers and body here, so I decided to use it. (You may also refer to RFC 1867.) The solution: a helper classTo simplify the process of making requests, I wrote the helper class (included in the archive), so adding a file to the form can be as simple as: private void webBrowser1_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
HtmlElement form = webBrowser1.Document.Forms[0];
form.AttachEventHandler("onsubmit", delegate(object o, EventArgs arg)
{
FormToMultipartPostData postData =
new FormToMultipartPostData(webBrowser1, form);
postData.SetFile("fileField", @"C:\windows\win.ini");
postData.Submit();
});
}
In the example above, I’m adding an event handler for the “ Here’s a more complicated (and more correct) example, which manages several forms on one page (adding private void webBrowser1_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
HtmlDocument doc = webBrowser1.Document;
for (int i = 0; i < doc.Forms.Count; i++)
{
// must be declared inside the loop because there's a closure
HtmlElement form = doc.Forms[i];
if (form.GetAttribute("enctype").ToLower() != "multipart/form-data") { continue; }
form.AttachEventHandler("onsubmit", delegate(object o, EventArgs arg)
{
FormToMultipartPostData postData =
new FormToMultipartPostData(webBrowser1, form);
postData.SetFile("file", @"C:\windows\win.ini");
postData.Submit();
});
form.SetAttribute("hasBrowserHandler", "1");
// expose that we have a handler to JS
}
}
The From the constructor, it loads all the values set in the form ( Because the class is rather large (compared to its modest functionality), I decided not to post it here. You can find it in the archive. Handling JavaScript: form.submit()By design, calling the private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
string url = e.Url.ToString();
if (url.StartsWith("submit:"))
{
string formId = url.Substring(7);
HtmlElement form = webBrowser1.Document.GetElementById(formId);
if (form != null) { form.RaiseEvent("onsubmit"); }
e.Cancel = true;
}
}
The trick is to set the window location to fake the URL which starts with “submit:” (the rest of this “pseudo-URL” is the form ID). If anyone knows a more elegant solution, please share it with me. You may have noted in the above “complicated example” of adding an form.SetAttribute("hasBrowserHandler", "1");
Thus, the JavaScript code needed to invoke the submit process should be something like this: function doSubmit(formId) {
var form = document.getElementById(formId);
if (form.getAttribute('hasBrowserHandler')) {
window.location = "submit:" + formId;
}
else {
form.submit();
}
}
The test scriptI also included a PHP script which might be useful in testing and debugging the class. CreditsThanks to Steven Cheng from Microsoft, who posted an example of making multipart messages, I did not have to write the main (and most difficult) part of the code. There’s also an example of the same task done using the I hope this solution will help you save some time (I spend a whole day to find the best way to solve this simple task.) Since at this time I am a newbie to C#, any feedback is appreciated.
|
|||||||||||||||||||||||||||||||||||||||||||||||