4

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.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
PiE
  • 335
  • 1
  • 7
  • 24
  • 1
    This is a testing automation script – PiE Sep 08 '13 at 21:28
  • That might be a browser security restriction. Are you able to do `SendKeys` into anything else but ``? – noseratio Sep 09 '13 at 01:03
  • Yes, I am able to use send keys. Apparently, someone has claimed that they can do this - I just can't recreate it - here is the Url: http://stackoverflow.com/questions/1696750/submit-file-in-form-from-c-sharp – PiE Sep 09 '13 at 01:06
  • You can do this using Selenium WebDriver using the IEDriver - here is the code: element = driver.FindElement(By.Name("file")); element.SendKeys("C:\\Images\\CCPhotoID.jpg"); – PiE Sep 09 '13 at 01:32
  • Selenium automates an out-of-process instance of IE, so it sends the keys to whatever IE window currently has focus (*Choose File* dialog in this case). Check my answer for a solution that works for `WebBrowser`. – noseratio Sep 09 '13 at 03:49

2 Answers2

7

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());
}
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • No problem, glad it helped :] If you're interested in more details on how Task.Delay works, you may want to check out [this](http://stackoverflow.com/a/18587810/1768303). – noseratio Sep 09 '13 at 07:17
  • Hi, how to do this on VB.NET? I try to convert this code on Telerik Converter, but i dont have sucess :/ – Sérgio Wilker Oct 13 '19 at 15:02
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

Community
  • 1
  • 1
  • thanks a lot for your comments, got mine program working, the key is to execute the sendKey before opening the file dialog! – ces2601 Dec 30 '21 at 23:42