Uploading Files Not Working - Need Assistance
I am trying to upload a file (an image) using the WebBrowser control. Can't seem to do it and need some help.
Here is the Html:
<form action="https://post.testsite.com/k/IOkurrwY4xGI_EJMbjF5pg/zMNsR" method="post" enctype="multipart/form-data">
<input type="hidden" name="cryptedStepCheck" value="U2FsdGVkX18yNzEwMjcxMJdrv2IidjtpGSCPzHNblWk02eJAJ6DFXFXic-Am1lTPMYL7k7XDoH0">
<input type="hidden" name="a" value="add">
<input class="file" type="file" name="file" multiple="multiple">
<button class="add" type="submit" name="go" value="add image">add image</button>
</form>
Here is the C# code...
elements = webBrowser.Document.GetElementsByTagName("input");
foreach (HtmlElement file in elements)
{
if (file.GetAttribute("name") == "file")
{
file.Focus();
file.InvokeMember("Click");
SendKeys.Send("C:\\Images\\CCPhotoID.jpg" + "{ENTER}");
}
}
Note that the file upload button comes up, but can't input any filename into the file name area.
Solution 1:
IMO, what you're trying to do is indeed a legit scenario for UI testing automation. IIRC, in early versions of IE it was possible to populate the <input type="file"/>
field with a file name, without showing up the Choose File
dialog. For security reason, this is no longer possible, so you have to send keys to the dialog.
The problem here is that file.InvokeMember("Click")
shows a modal dialog, and you want the keys to be sent to that dialog, but SendKeys.Send
gets executed after the dialog has been closed (it's modal, after-all). You need to let the dialog open first, then send the keys and let it close.
This problem can be solved using WinForms Timer
, but I'd prefer using async/await
and Task.Delay
for this (working code):
async Task PopulateInputFile(HtmlElement file)
{
file.Focus();
// delay the execution of SendKey to let the Choose File dialog show up
var sendKeyTask = Task.Delay(500).ContinueWith((_) =>
{
// this gets executed when the dialog is visible
SendKeys.Send("C:\\Images\\CCPhotoID.jpg" + "{ENTER}");
}, TaskScheduler.FromCurrentSynchronizationContext());
file.InvokeMember("Click"); // this shows up the dialog
await sendKeyTask;
// delay continuation to let the Choose File dialog hide
await Task.Delay(500);
}
async Task Populate()
{
var elements = webBrowser.Document.GetElementsByTagName("input");
foreach (HtmlElement file in elements)
{
if (file.GetAttribute("name") == "file")
{
file.Focus();
await PopulateInputFile(file);
}
}
}
IMO, this approach is very convenient for UI automation scripts. You can call Populate
like this, for example:
void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
this.webBrowser.DocumentCompleted -= webBrowser_DocumentCompleted;
Populate().ContinueWith((_) =>
{
MessageBox.Show("Form populated!");
}, TaskScheduler.FromCurrentSynchronizationContext());
}
Solution 2:
Just simple like that
elements = webBrowser.Document.GetElementsByTagName("input");
foreach (HtmlElement file in elements)
{
if (file.GetAttribute("name") == "file")
{
SelectFile();
file.InvokeMember("Click");
}
}
Make this function and call it before click it will work perfectly
public async void SelectFile()
{
await Task.Delay(2000);
SendKeys.Send("C:\\Images\\CCPhotoID.jpg" + "{ENTER}");
}
and no triming character error as I faced Take a look on this I was posted this Question