在C#中调用JavaScript等脚本的实现<转>

简介:
在C#中调用JavaScript等脚本的实现
作者:秋枫 发布时间:2004-4-29 9:49:05 文章来源:csdn

以前在做工作流(workflow)项目的时候,里面有一项就是在用户制定流程定义时可以编写脚本来控制活动的跳转,而这些脚本定义后存在数据库中,当流程启动的时候,工作流引擎会控制活动执行顺序,串型的两个活动比较简单,但有的活动到下一个活动有条件判断,或者存在多个分支,简单的还好,只要在数据库表中加个字段就可以实现,复杂一点的就需要通过脚本实现了。当时经验不够,几天都没找到快速的解决办法,想自己写一个自定义脚本引擎没有把握,而且时间也不够,还是在网上找找看吧,花了一些时间,还是找到了一个自认为比较好的解决办法,写出来同大家分享。
下面通过两部分来说明实现以及应用。

一.使用MSScriptControl

到微软的网站上下载Windows Script Control,它是一个ActiveX(R) 控件,所以在.NET中使用我Interop了一下。下载安装完成后,新建一个C#的Windows应用程序项目,在解决方案资源管理器中选中引用节点,右键点击选择添加引用菜单,弹出添加引用对话框,单击浏览找到安装Windows Script Control的目录,选取msscript.ocx文件确定。那么在引用节点下会增加一个MSScriptControl组件,下面是他Interop后的所有对象。

ScriptControl 对支持 ActiveX(TM) Script 的宿主 Script 引擎提供简单接口。接下来我们对被转化成ScriptControlClass类的ScriptControl的属性和方法进行一些说明。

属性

AllowUI 属性:应用于 ScriptControl 本身或 Scirpt 引擎显示的用户界面元素,可读写。

CodeObject 属性:返回对象,该对象用于调用指定模块的公用成员。只读。

Error 属性:返回 Error 对象,其中包含所发生的最后一个错误的相关详细信息。只读。

Language 属性:设置或返回正在使用的 Script 语言名称。可读写。

Modules 属性:为 ScriptControl 对象返回模块集合。只读。

Procedures 属性:返回在指定模块中定义的过程集合。只读。

SitehWnd 属性:设置或返回窗口的 hWnd,通过执行 Script 代码,此窗口用于显示对话框和其他用户界面元素。可读写。

State 属性:设置或返回 ScriptControl 对象的模式。可读写。

Timeout 属性:设置或返回时间(毫秒),此时间后用户可选择中止 Script 代码的执行或允许代码继续执行。可读写。

UseSafeSubset 属性:设置或返回 Boolean 值,指明宿主应用程序是否有保密性要求。如果宿主应用程序需要安全控制,则 UseSafeSubset 为 True,否则为 False。可读写。

方法

AddCode 方法:向模块添加指定代码。可多次调用 AddCode 方法。

AddObject 方法:使主机对象模型对 Script 引擎可用。

Eval 方法:计算表达式并返回结果。

ExecuteStatement 方法:执行指定的语句。

Reset 方法:放弃所有已经添加到 ScriptControl 中的 Script 代码和对象。

Run 方法:运行指定过程。

事件

Error 事件:出现运行时错误时,发生此事件。

Timeout 事件:当超出了 Timeout 属性指定的时间且用户在结果对话框中选定了 End 时,发生此事件。

补充几点

AllowUI 属性如果设置为false,则显示对话框之类的语句不起作用,如在 VBScript 中MsgBox 语句,JavaScript中的alert等,并且如果执行的脚本超出TimeOut设置的毫秒数,也不会跳出超出时间提醒的对话框,反之则相反;重新设置 Language 属性会清空AddCode加载的代码;对于TimeOut属性,发生超时时,ScriptControl 检查对象的 AllowUI 属性,确定是否允许显示用户界面元素。

如果读者需要更详细的了解,可以查看MSDN文档。

为了使控件更容易使用,我用一个ScriptEngine类包装了一下,下面是完整代码:

?
using System;
 
using MSScriptControl;
 
using System.Text;
 
namespace ZZ
 
{
 
      /// <summary>
 
      /// 脚本类型
 
      /// </summary>
 
      public enum ScriptLanguage
 
      {
 
          /// <summary>
 
          /// JScript脚本语言
 
          /// </summary>
 
          JScript,
 
          /// <summary>
 
          /// VBscript脚本语言
 
          /// </summary>
 
          VBscript,
 
          /// <summary>
 
          /// JavaScript脚本语言
 
          /// </summary>
 
          JavaScript
 
      }
 
      /// <summary>
 
      /// 脚本运行错误代理
 
      /// </summary>
 
      public delegate void RunErrorHandler();
 
      /// <summary>
 
      /// 脚本运行超时代理
 
      /// </summary>
 
      public delegate void RunTimeoutHandler();
 
      /// <summary>
 
      /// ScriptEngine类
 
      /// </summary>
 
      public class ScriptEngine
 
      {
 
          private ScriptControl msc;
 
          //定义脚本运行错误事件
 
          public event RunErrorHandler RunError;
 
          //定义脚本运行超时事件
 
          public event RunTimeoutHandler RunTimeout;
 
          /// <summary>
 
          ///构造函数
 
          /// </summary>
 
          public ScriptEngine(): this (ScriptLanguage.VBscript)
 
          {
 
          }
 
          /// <summary>
 
          /// 构造函数
 
          /// </summary>
 
          /// <param name="language">脚本类型</param>
 
          public ScriptEngine(ScriptLanguage language)
 
          {
 
               this .msc = new ScriptControlClass();
 
               this .msc.UseSafeSubset = true ;
 
               this .msc.Language = language.ToString();
 
               ((DScriptControlSource_Event) this .msc).Error += new DScriptControlSource_ErrorEventHandler(ScriptEngine_Error);
 
               ((DScriptControlSource_Event) this .msc).Timeout += new DScriptControlSource_TimeoutEventHandler(ScriptEngine_Timeout);
 
          }
 
          /// <summary>
 
          /// 运行Eval方法
 
          /// </summary>
 
          /// <param name="expression">表达式</param>
 
          /// <param name="codeBody">函数体</param>
 
          /// <returns>返回值object</returns>
 
          public object Eval( string expression, string codeBody)
 
          {
 
               msc.AddCode(codeBody);
 
               return msc.Eval(expression);
 
          }
 
          /// <summary>
 
          /// 运行Eval方法
 
          /// </summary>
 
          /// <param name="language">脚本语言</param>
 
          /// <param name="expression">表达式</param>
 
          /// <param name="codeBody">函数体</param>
 
          /// <returns>返回值object</returns>
 
          public object Eval(ScriptLanguage language, string expression, string codeBody)
 
          {
 
               if ( this .Language != language)
 
                    this .Language = language;
 
               return Eval(expression,codeBody);
 
          }
 
          /// <summary>
 
          /// 运行Run方法
 
          /// </summary>
 
          /// <param name="mainFunctionName">入口函数名称</param>
 
          /// <param name="parameters">参数</param>
 
          /// <param name="codeBody">函数体</param>
 
          /// <returns>返回值object</returns>
 
          public object Run( string mainFunctionName, object [] parameters, string codeBody)
 
          {
 
               this .msc.AddCode(codeBody);
 
               return msc.Run(mainFunctionName, ref parameters);
 
           }
 
          /// <summary>
 
          /// 运行Run方法
 
          /// </summary>
 
          /// <param name="language">脚本语言</param>
 
          /// <param name="mainFunctionName">入口函数名称</param>
 
          /// <param name="parameters">参数</param>
 
          /// <param name="codeBody">函数体</param>
 
          /// <returns>返回值object</returns>
 
          public object Run(ScriptLanguage language, string mainFunctionName, object [] parameters, string codeBody)
 
          {
 
               if ( this .Language != language)
 
                    this .Language = language;
 
               return Run(mainFunctionName,parameters,codeBody);
 
          }
 
          /// <summary>
 
          /// 放弃所有已经添加到 ScriptControl 中的 Script 代码和对象
 
          /// </summary>
 
          public void Reset()
 
          {
 
               this .msc.Reset();
 
          }
 
          /// <summary>
 
          /// 获取或设置脚本语言
 
          /// </summary>
 
          public ScriptLanguage Language
 
          {
 
               get { return (ScriptLanguage)Enum.Parse( typeof (ScriptLanguage), this .msc.Language, false );}
 
               set { this .msc.Language = value.ToString();}
 
          }
 
          /// <summary>
 
          /// 获取或设置脚本执行时间,单位为毫秒
 
          /// </summary>
 
          public int Timeout
 
          {
 
               get { return this .msc.Timeout;}
 
               set { this .msc.Timeout = value;}
 
          }
 
          /// <summary>
 
          /// 设置是否显示用户界面元素
 
          /// </summary>
 
          public bool AllowUI
 
          {
 
               get { return this .msc.AllowUI;}
 
               set { this .msc.AllowUI = value;}
 
          }
 
          /// <summary>
 
          /// 宿主应用程序是否有保密性要求
 
          /// </summary>
 
          public bool UseSafeSubset
 
          {
 
               get { return this .msc.UseSafeSubset;}
 
               set { this .msc.UseSafeSubset = true ;}
 
          }
 
          /// <summary>
 
          /// RunError事件激发
 
          /// </summary>
 
          private void OnError()
 
          {
 
               if (RunError!= null )
 
                    RunError();
 
          }
 
          /// <summary>
 
          /// OnTimeout事件激发
 
          /// </summary>
 
          private void OnTimeout()
 
          {
 
               if (RunTimeout!= null )
 
                    RunTimeout();
 
          }
 
          private void ScriptEngine_Error()
 
          {
 
               OnError();
 
          }
 
          private void ScriptEngine_Timeout()
 
          {
 
               OnTimeout();
 
          }
 
      }
 
}
 
上面的包装定义了一个ScriptLanguage枚举,这样操作起来更方便一点。另外脚本引擎包括了Error事件和Timeout事件,根据实际使用情况可进行注册。
 
  
 
二.脚本引擎演示
 
      我建了个窗体程序,测试包括脚本语言的选择,是否开启AllowUI属性,超时时间的设置,以及脚本引擎调用方法的选择。测试程序代码比较长,下面列出了主要部分:
 
using System;
 
using System.Drawing;
 
using System.Collections;
 
using System.ComponentModel;
 
using System.Windows.Forms;
 
using System.Data;
 
namespace ZZ
 
{
 
      public class Form1 : System.Windows.Forms.Form
 
      {
 
          private ScriptEngine scriptEngine;
 
          private System.Windows.Forms.CheckBox checkBoxAllowUI;
 
          private System.Windows.Forms.TextBox textBoxResult;
 
          private System.Windows.Forms.NumericUpDown numericUpDownTimeout;
 
          private System.Windows.Forms.TextBox textBoxCodeBody;
 
          private System.Windows.Forms.Button buttonRun;
 
          private System.Windows.Forms.Button buttonCancel;
 
          private System.Windows.Forms.ComboBox comboBoxScript;
 
          private System.Windows.Forms.TextBox textBoxParams;
 
          private System.Windows.Forms.RadioButton radioButtonEval;
 
          private System.Windows.Forms.RadioButton radioButtonRun;
 
          private System.Windows.Forms.TextBox textBoxMethodName;
 
          private System.ComponentModel.Container components = null ;
 
  
 
          public Form1()
 
          {
 
               InitializeComponent();
 
               this .comboBoxScript.SelectedIndex = 0;
 
               this .scriptEngine = new ScriptEngine();
 
               this .scriptEngine.UseSafeSubset = true ;
 
               this .scriptEngine.RunError += new RunErrorHandler(scriptEngine_RunError);
 
               this .scriptEngine.RunTimeout += new RunTimeoutHandler(scriptEngine_RunTimeout);
 
          }
 
          protected override void Dispose( bool disposing )
 
          {
 
               if ( disposing )
 
                    if (components != null )
 
                        components.Dispose();
 
               base .Dispose( disposing );
 
          }
 
          #region Windows 窗体设计器生成的代码
 
          private void InitializeComponent()
 
          {
 
               //省略
 
          }
 
          #endregion
 
           [STAThread]
 
          static void Main()
 
          {
 
               Application.Run( new Form1());
 
          }
 
          //运行脚本
 
          private void buttonRun_Click( object sender, System.EventArgs e)
 
          {
 
               this .scriptEngine.Reset();
 
               this .scriptEngine.Language = (ScriptLanguage)Enum.Parse( typeof (ScriptLanguage), this .comboBoxScript.SelectedItem.ToString());
 
               this .scriptEngine.Timeout = ( int ) this .numericUpDownTimeout.Value;
 
               this .scriptEngine.AllowUI = this .checkBoxAllowUI.Checked;
 
               if ( this .radioButtonEval.Checked) //执行Eval方法
 
               {
 
                    this .textBoxResult.Text = this .scriptEngine.Eval( this .textBoxMethodName.Text+ "(" + this .textBoxParams.Text+ ")" , this .textBoxCodeBody.Text).ToString();
 
               }
 
               else //执行Run方法
 
               {
 
                    string [] parameters = ( string []) this .textBoxParams.Text.Split( ',' );
 
                    object [] paramArray = new object [parameters.Length];
 
                    for ( int i = 0;i<parameters.Length;i++)
 
                        paramArray[i] = Int32.Parse(parameters[i]);
 
                    this .textBoxResult.Text = this .scriptEngine.Run( this .textBoxMethodName.Text,paramArray, this .textBoxCodeBody.Text).ToString();
 
               }
 
          }
 
          //退出程序
 
          private void buttonCancel_Click( object sender, System.EventArgs e)
 
          {
 
               this .Close();
 
          }
 
          //错误函数
 
          private void scriptEngine_RunError()
 
          {
 
               MessageBox.Show( "RunError执行脚本错误!" );
 
          }
 
          private void scriptEngine_RunTimeout()
 
          {
 
               MessageBox.Show( "RunTimeout执行脚本超时,引发错误!" );
 
          }
 
      }
 
}


下面是测试程序运行界面:

在文本框中写了一个JavaScript的函数。输入12,输出12000012。

如果把超时时间调整为1毫秒,那么执行该脚本就会跳出下面的超时提醒框,同时激发事件。

  总结,上面演示了JavaScript脚本,如果有兴趣读者可以写一些VBsript函数进行测试,脚本语言也只列出了三种,看了帮助,他还支持其他一些脚本,如果需要可以添加。另外,因为是调用Com,有些返回值是obejct类型的,需要进行转换。在CSDN的技术论坛C#板块下时常有朋友问这方面的问题,对于碰到这类问题的朋友,希望通过这篇文章能获得一些你需要的帮助,很高兴能和搞.net的朋友进行交流,我的邮件地址zhzuocn@163.com

 

 

本文转自温景良(Jason)博客园博客,原文链接:http://www.cnblogs.com/wenjl520/archive/2011/06/30/2095089.html,如需转载请自行联系原作者

相关文章
|
开发框架 前端开发 JavaScript
C# 6.0+JavaScript云LIS系统源码  云LIS实验室信息管理新型解决方案
云LIS是为区域医疗提供临床实验室信息服务的计算机应用程序,可协助区域内所有临床实验室相互协调并完成日常检验工作,对区域内的检验数据进行集中管理和共享,通过对质量控制的管理,最终实现区域内检验结果互认。其目标是以医疗服务机构为主体,以医疗资源和检验信息共享为目标,集成共性技术及医疗服务关键技术,建立区域协同检验,最大化利用有限的医疗卫生资源。
449 1
|
JavaScript 前端开发 测试技术
使用Selenium执行JavaScript脚本:探索Web自动化的新领域
本文介绍了如何在Selenium中使用JavaScript解决自动化测试中的复杂问题。Selenium的`execute_script`函数用于同步执行JS,例如滑动页面、操作时间控件等。在滑动操作示例中,通过JS将页面滚动到底部,点击下一页并获取页面信息。对于只读时间控件,利用JS去除readonly属性并设置新日期。使用JS扩展了Selenium的功能,提高了测试效率和精准度,适用于各种自动化测试场景。
|
JavaScript 前端开发 安全
C#结合JavaScript实现多文件上传
C#结合JavaScript实现多文件上传
|
JavaScript Shell C#
多种脚本批量下载 Docker 镜像:Shell、PowerShell、Node.js 和 C#
本项目提供多种脚本(Shell、PowerShell、Node.js 和 C#)用于批量下载 Docker 镜像。配置文件 `docker-images.txt` 列出需要下载的镜像及其标签。各脚本首先检查 Docker 是否安装,接着读取配置文件并逐行处理,跳过空行和注释行,提取镜像名称和标签,调用 `docker pull` 命令下载镜像,并输出下载结果。使用时需创建配置文件并运行相应脚本。C# 版本需安装 .NET 8 runtime。
1361 3
|
JSON 移动开发 JavaScript
在浏览器执行js脚本的两种方式
【10月更文挑战第20天】本文介绍了在浏览器中执行HTTP请求的两种方式:`fetch`和`XMLHttpRequest`。`fetch`支持GET和POST请求,返回Promise对象,可以方便地处理异步操作。`XMLHttpRequest`则通过回调函数处理请求结果,适用于需要兼容旧浏览器的场景。文中还提供了具体的代码示例。
477 5
在浏览器执行js脚本的两种方式
|
安全 Java C#
Unreal Engine C# 脚本编写浅谈
本文介绍了在 Unreal Engine 中使用 C# 编写脚本的方法,涵盖环境搭建、基础概念、常见问题及代码案例。从安装插件到处理输入事件和加载蓝图,详细讲解了如何在 Unreal Engine 中高效利用 C# 进行开发。
801 3
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
1097 1
|
JavaScript 前端开发 NoSQL
【MongoDB 专栏】MongoDB 的 JavaScript 引擎与脚本执行
【5月更文挑战第11天】MongoDB 的 JavaScript 引擎允许在服务器端直接执行脚本,提升效率并实现定制化操作。脚本环境提供独立但与数据库关联的运行空间,引擎负责脚本的解析、编译和执行。执行过程包括脚本提交、解析、编译和执行四个步骤。掌握脚本逻辑设计和 JavaScript 语言特性对于高效利用这一功能至关重要。例如,通过脚本可以计算商品总销售额,增强数据库操作的灵活性。
493 1
【MongoDB 专栏】MongoDB 的 JavaScript 引擎与脚本执行
|
JavaScript 前端开发
用JavaScript脚本将当地时间转换成其它时区
用JavaScript脚本将当地时间转换成其它时区
|
JavaScript 前端开发
Playwright执行 JavaScript 脚本:探索浏览器自动化的新境界
在Web自动化中,Playwright提供`page.evaluate()`和`page.evaluate_handle()`来执行JavaScript脚本。`page.evaluate()`返回脚本执行结果,而`page.evaluate_handle()`返回JSHandle。示例展示了如何使用它们,如打印网页标题、操作元素及获取页面内容。通过这些方法,可以处理常规方法难以操作的网页元素。