实用主义

把.Net用好用足

导航

网站复杂信息自动录入处理

问题:某某系统是基于B/S的,无法获得数据接口,有信息录入页面,该信息录入页面是基于showModalDialog的,且录入完初步信息后会redirect到另一URL(假设原URL为URL1,重定向后URL为URL2),其他的信息在URL2中要通过javascript切换链接(像TAB页效果一样)才能继续录入,录入过程中有可能提交后有alert信息提示,现有待数据一堆(1000条),要求实现数据的程序自动化录入。

解决方案:使用ExtendedWebBrowser处理,用WebBrowser打开URL1,取得HTML文档后自动填写表单,然后调用提交函数,待转向URL2后,再调用Javascript函数转向其他信息录入页面,并自动填写表单,调用保存JS函数,一条记录的所有信息录入完成后,转向URL1,重新开始,录入下一条数据。

几个技术点:
1.目标系统中showModalDialog出来的页面无状态条,无法知道URL1。
解决:先通过ieHttpHeaders跟踪showModalDialog,取得URL1的实际值。

2.无法得知录入页面是否加载完成。
解决:在DocumentCompleted事件处理程序中判断ReadyState后,加入输出e.url语句,启动自已基于ExtendedWebBrowser开发的浏览器程序,把各步骤中表单可以自动填单后的最后输出的那个URL记录下来,形成各步骤的特征URL,这样就能处理frames和Iframe及JS中加载的页面。如:
void brw_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
      {
          if (_windowManager.ActiveBrowser.ReadyState == WebBrowserReadyState.Complete)
          {
              SouthHIS.modOutputLog.OutputLog(e.Url.ToString());
           }
        }
记录下来的有:
步骤1:http://xxx.xxx/BasicInfo.aspx?OpFlag=add&strGuardNo=
步骤2:http://xxx.xxx/aaedit2.aspx
步骤2:http://xxx.xxx/aaedit3.aspx

3.各步骤填写表单有可能出错而要重复执行,如何让各步骤确定地执行完成上一步后再执行下一步并串起来.
解决:使用状态机方案,画好状态机图,然后定义一个变量表示状态机状态,执行成功一个步骤后,改变状态变量以让状态机执行下一动作,如果执行不成功,可以返回重新执行,或是返回上一步再重新加载等。

4.程序执行速度过快,即使程序表明页面载完成,自动填入表单时还是会发生一些页面里的onload时执行的未完成,导致后续填写表单或执行JS出错.即:判断出某步骤“加载完”最后的页面URL,执行填单程序,有时还是会出错,如何处理。
解决:使用多线程,让步骤执行在非主线程上执行,在满足载条件后再等待一段时间,让WebBrowser加载彻底完成后,再使用invoke来执行各步骤的填单程序.
样例程序:
 public    class InvokeObject
      {
          public System.Threading.ThreadStart m_func;
          public MainForm m_frm;
          public  InvokeAA(System.Threading.ThreadStart func,MainForm frm)
          {
              m_func = func;
              m_frm = frm;
          }
          public void ToThreadCall()
          {
              DateTime dt1 = DateTime.Now;
              while (true)//等待“加载完成”后再等待200MS
              {
                  Application.DoEvents();
                  DateTime dt2 = DateTime.Now;
                  TimeSpan ts = dt2.Subtract(dt1);
                  if (ts.Milliseconds > 200)
                  {
                      break;
                  }
              }
              m_frm.Invoke(m_func);//执行真正的步骤处理函
          }
      }

使用代码:
          InvokeAA abc = new InvokeAA(GoToFamilyPage, this);//GoToFamilyPage是步骤处理函数
          System.Threading.Thread th2 = new System.Threading.Thread(abc.ToThreadCall);
          th2.Name = "GoToFamilyPage";
          th2.Start();

5.如何拦截alert对话框,以让其继续.
解决:扩展WebBrowser,处理  ShowMessage.在extendedWebBrowser中,加入代码:
//拦截alert
    #region ExtendedWebBrowserSite
    class ExtendedWebBrowserSite : WebBrowser.WebBrowserSite, UnsafeNativeMethods.IDocHostShowUI
    {
        WebBrowser m_host;
        public ExtendedWebBrowserSite(WebBrowser host)
            : base(host)
        {
            m_host = host;
        }
        void UnsafeNativeMethods.IDocHostShowUI.ShowMessage(ref UnsafeNativeMethods._RemotableHandle hwnd, string lpstrText, string lpstrCaption, uint dwType, string lpstrHelpFile, uint dwHelpContext, out int plResult)
        {
            //TODO:自定义处理弹出消息框
            //dwType:0x00000030问题
            SouthHIS.modOutputLog.OutputLog(lpstrText);
            SouthHIS.modOutputLog.OutputLog(dwType);
            if (dwType != 0x00000030)
            {

                //plResult = (int)System.Windows.Forms.MessageBox.Show(lpstrText, lpstrCaption, (MessageBoxButtons)dwType );
            }
            plResult = 1;
        }
        void UnsafeNativeMethods.IDocHostShowUI.ShowHelp(ref UnsafeNativeMethods._RemotableHandle hwnd, string pszHelpFile, uint uCommand, uint dwData, UnsafeNativeMethods.tagPOINT ptMouse, object pDispatchObjectHit)
        {
            //TODO:自定义处理弹出帮助消息框
        }
    }

      protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
      {
          return new ExtendedWebBrowserSite(this);
      }

6.如何拦截执行JS出错时弹出的脚本错误对话框
解决:在加载页面前,使用:
 brw.ScriptErrorsSuppressed = true;
让其不显示对话框.

7.如何取得frames,如何执行javascript,如何定义额外的javascript函数,如何取得执行javascript函数的返回值。
解决:
          HtmlWindow win1 = _windowManager.ActiveBrowser.Document.Window.Frames[0];
          mshtml.IHTMLWindow2 win2 = (mshtml.IHTMLWindow2)win1.DomWindow;         
          try
          {
             string script11 = "function SaveRow11() { return '0';}";
             win2.execScript(script11, "javascript");
             string strRetVal = (string)win1.Document.InvokeScript("SaveRow11");
             if(strRetVal =='0')
             {
                ....
              }
           }catch .....
          




posted on 2008-12-11 12:11  Render  阅读(2139)  评论(0编辑  收藏  举报