Downloading a file with Watin in IE9

我的未来我决定 提交于 2019-11-27 04:34:41

问题


I'm having an issue with automating the process of downloading a file from a website. The website has a Java button, that when clicked, triggers the download of an Excel file. I'm using the most recent build of Watin (v2.1).

I've managed to get Watin to log into the website, navigate to the appropriate page, change parameters on the page, and click the button to start the download.

However, when the download has completed, the IE9 download box appears, and nothing happens, until Watin timesout.

I'd appreciate any suggestions as I can't see any way of downloading a file, or getting it to save the file. Even if it passed 'Alt+S' to the page, that would save it. I've tried running it through WatinTestRecorder and that doesn't prompt for saving.

using (var browser = new IE(sLogin))
{
    browser.AddDialogHandler(new OKDialogHandler());
    browser.AddDialogHandler(new DialogHandlerHelper());
    browser.AddDialogHandler(new ConfirmDialogHandler());
    browser.AddDialogHandler(new ReturnDialogHandlerIe9());

    browser.TextField(Find.ByName("txtUserID")).TypeText("username");
    browser.TextField(Find.ByName("txtPassword")).TypeText("password");
    browser.Button(Find.ByName("btnLogin")).Click();

    browser.WaitForComplete();  
    browser.GoTo(targetUri);

    browser.SelectList("ctl00_phFormContent_ucOptionParam0_lst").SelectByValue("4");

    browser.Button(Find.ByName("ctl00$phFormButtonBar$btnRun")).Click();
    browser.WaitForComplete();

    //Some code to download the file here!
}

回答1:


This should be supported since version 1.1.0.4000. The release notes for that version aren't online anymore (http://watin.org/documentation/), but I found it in Googles cache (http://svn6.assembla.com/svn/ci-samples/dotnet/watir/website/releasenotes-1-1-0-4000.html)

It should be something like:

using(IE ie = new IE(someUrlToGoTo))
{
    FileDownloadHandler fileDownloadHandler = new FileDownloadHandler(fullFileName);
    ie.AddDialogHandler(fileDownloadHandler);

    ie.Link("startDownloadLinkId").Click();

    fileDownloadHandler.WaitUntilFileDownloadDialogIsHandled(15);
    fileDownloadHandler.WaitUntilDownloadCompleted(200);
}

EDIT: After the comments below, this answer was accepted. So I'm assuming the following code works (which is taken from the link to SourceForge in my last comment, notice the ClickNoWait):

using(IE ie = new IE(someUrlToGoTo))
{
    FileDownloadHandler fileDownloadHandler = new FileDownloadHandler(fullFileName);
    ie.AddDialogHandler(fileDownloadHandler);

    ie.Link("startDownloadLinkId").ClickNoWait();

    fileDownloadHandler.WaitUntilFileDownloadDialogIsHandled(15);
    fileDownloadHandler.WaitUntilDownloadCompleted(200);
}



回答2:


The accepted answer did not work for me because IE 9 pops up a "Notification" you have to navigate before you can get to the actual Save As dialog (and WatiN cannot handle notifications automatically). I followed Borris Pavlov's link which did a good job showing the way. I cleaned up the code a bit that was posted there and this was the resulting file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WatiN.Core;
using WatiN.Core.Native.Windows;
using System.Threading;
using System.Windows.Automation;

namespace MyProject
{
    public static class BrowserExtensionMethods
    {
        public static void DownloadIeFile(this IE browser,string saveAsFilename=null)
        {
            // see information here (http://msdn.microsoft.com/en-us/library/windows/desktop/ms633515(v=vs.85).aspx)
            Window windowMain = new Window(NativeMethods.GetWindow(browser.hWnd, 5));
            TreeWalker dialogElementTreeWalker = new TreeWalker(Condition.TrueCondition);
            AutomationElement mainWindow = dialogElementTreeWalker.GetParent(AutomationElement.FromHandle(browser.hWnd));

            Window windowDialog = new Window(NativeMethods.GetWindow(windowMain.Hwnd, 5));
            // if doesn't work try to increase sleep interval or write your own waitUntill method
            Thread.Sleep(1000);
            windowDialog.SetActivate();
            AutomationElementCollection dialogElements = AutomationElement.FromHandle(windowDialog.Hwnd).FindAll(TreeScope.Children, Condition.TrueCondition);

            if (string.IsNullOrEmpty(saveAsFilename))
            {
                ClickSave(dialogElements);
            }
            else
            {
                ClickSaveAs(mainWindow, dialogElements,saveAsFilename);
            }
        }

        private static void ClickSaveAs(AutomationElement mainWindow, AutomationElementCollection dialogElements,string filename)
        {
            foreach (AutomationElement element in dialogElements)
            {

                if (element.Current.Name.Equals("Save"))
                {
                    AutomationElementCollection dialogSubElements = element.FindAll(TreeScope.Children, Automation.ControlViewCondition);
                    InvokePattern clickPatternForSaveDropdown = (InvokePattern)dialogSubElements[0].GetCurrentPattern(AutomationPattern.LookupById(10000));
                    clickPatternForSaveDropdown.Invoke();
                    Thread.Sleep(3000);

                    AutomationElementCollection dialogElementsInMainWindow = mainWindow.FindAll(TreeScope.Children, Condition.TrueCondition);
                    foreach (AutomationElement currentMainWindowDialogElement in dialogElementsInMainWindow)
                    {
                        if (currentMainWindowDialogElement.Current.LocalizedControlType == "menu")
                        {
                            // first array element 'Save', second array element 'Save as', third second array element    'Save and open'
                            InvokePattern clickMenu = (InvokePattern)currentMainWindowDialogElement.FindAll(TreeScope.Children, Condition.TrueCondition)[1].GetCurrentPattern(AutomationPattern.LookupById(10000));
                            clickMenu.Invoke();
                            Thread.Sleep(5000);
                            ControlSaveDialog(mainWindow, filename);
                            break;

                        }
                    }
                }
            }
        }

        private static void ClickSave(AutomationElementCollection dialogElements)
        {
            foreach (AutomationElement element in dialogElements)
            {
                // You can use "Save ", "Open", ''Cancel', or "Close" to find necessary button Or write your own enum
                if (element.Current.Name.Equals("Save"))
                {
                    // if doesn't work try to increase sleep interval or write your own waitUntil method
                    // WaitUntilButtonExsist(element,100);
                    Thread.Sleep(1000);
                    AutomationPattern[] automationPatterns = element.GetSupportedPatterns();
                    // replace this foreach if you need 'Save as' with code bellow
                    foreach (AutomationPattern currentPattern in automationPatterns)
                    {
                        // '10000' button click event id 
                        if (currentPattern.Id == 10000)
                        {
                            InvokePattern click = (InvokePattern)element.GetCurrentPattern(currentPattern);
                            click.Invoke();
                        }
                    }
                }
            }
        }

        private static void ControlSaveDialog(AutomationElement mainWindow, string path)
        {
            //obtain the save as dialog
            //*** must disable throwing of the NonComVisibleBaseClass "exception" for this to work in debug mode:
            //              1. Navigate to Debug->Exceptions...
            //              2. Expand "Managed Debugging Assistants"
            //              3. Uncheck the NonComVisibleBaseClass Thrown option.
            //              4. Click [Ok]
            //***copied from http://social.msdn.microsoft.com/Forums/en-US/27c3bae8-41fe-4db4-8022-e27d333f714e/noncomvisiblebaseclass-was-detected?forum=Vsexpressvb

            var saveAsDialog = mainWindow.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Save As"));
            //var saveAsDialog = mainWindow.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "[#] Save As [#]"));  //needed if using sandboxie
            //get the file name box
            var saveAsText = saveAsDialog
                    .FindFirst(TreeScope.Descendants,
                               new AndCondition(
                                   new PropertyCondition(AutomationElement.NameProperty, "File name:"),
                                   new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Edit)))
                    .GetCurrentPattern(ValuePattern.Pattern) as ValuePattern;
            //fill the filename box 
            saveAsText.SetValue(path);

            Thread.Sleep(1000);
            //find the save button
            var saveButton =
                    saveAsDialog.FindFirst(TreeScope.Descendants,
                    new AndCondition(
                        new PropertyCondition(AutomationElement.NameProperty, "Save"),
                        new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)));
            //invoke the button
            var pattern = saveButton.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
            pattern.Invoke();
        }
    }
}

See the comment in the ControlSaveDialog method for info on how to make this work as a debug build (VS settings).

I actually only tested the "Save As" operation so I hope the other works (it seems that the original poster added the "Save As" as an afterthought so my guess is that he tested the "Save" operation more thoroughly).

To call this you can use some code like:

Link lastMp4Link = mp4Links[mp4Links.Count - 1];  //mp4Links is a WatiN.Core.LinkCollection
lastMp4Link.Click();

browser.DownloadIeFile(string.Format(@"c:\temp\myFile.blah"));  //"browser" is a WatiN.Core.IE object



回答3:


I just got word from the Watin-users mailing list that FileDownloadHandler is broken with IE9. There is no fix yet, however I uninstalled IE9 (roll back to IE8) and it has the old style dialog that is handled by WatiN.




回答4:


Watin can't find download dialog and dialog buttons. It can resolve with this.

How to test file download with Watin / IE9?

See comments




回答5:


After many revisions using WaitN, I ended up using Selenium. It gives you a ton more control over what is being processed and used and allows you to use more modern web browsers.



来源:https://stackoverflow.com/questions/6125285/downloading-a-file-with-watin-in-ie9

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!