.NET应用程序的脚本支持库

在构建解析器等工具时,有时需要在应用程序中执行JavaScript,无论是为了抓取数据、提供脚本支持,还是为了模拟旧版的ASP。Microsoft提供了COM接口来使用这些脚本,但直接在.NET中使用它们并不优雅。幸运的是,创建了一个小巧的库,可以简化这一过程。

概念化这个混乱

Microsoft提供了一个可扩展的脚本框架,它在旧版ASP页面和Internet Explorer中使用。默认情况下,Windows附带了VBScriptJavaScript(JScript),但第三方也添加了其他脚本语言。这些脚本引擎是COM可见的,并将它们的脚本作为可以调用代码或被代码调用的COM对象公开。唯一的问题是接口比较混乱。

所做的是将这些接口封装在两个易于使用的对象中,即ScriptHostScriptEngine

使用这个混乱

首先,脚本引擎不能独立存在。它们需要一个扎根的地方,这就是ScriptHost的作用。ScriptHost管理脚本引擎的创建和生命周期,同时为脚本引擎提供各种服务,如错误报告和对象检索。在创建任何脚本引擎之前,必须创建一个这样的小东西。记得完成后要释放它。关闭脚本宿主也会关闭由它创建的所有引擎。

接下来,有ScriptEngine,可以通过ScriptHost.Create()获得。这些代表脚本代码的独立区域。为了理解这意味着什么,要知道每个网页中的<script>块将对应于这些中的一个,而页面本身将是ScriptHost。传递一个语言到Create()以获得想要的语言的脚本引擎。有一个“快速”的JS引擎,可以通过传递ChakraJS常量来访问,但没有测试过,也不确定它到底有多快。

有了ScriptEngine,可以Evaluate()表达式,Run()语句,或者AddCode()到脚本块。还可以将对象添加到Globals字典中,然后可以在脚本代码中通过名称访问这些对象。

希望以下示例代码能清楚地说明一切:

C# Console.WriteLine("Creating script host"); using(var host = new ScriptHost()) { // create a JavaScript engine Console.WriteLine("Creating javascript engine"); var engine = host.Create("javascript"); // you can use the ChakraJS const here // for IE9+'s fast engine // evaluate an expression Console.WriteLine("Evaluate 2+2: "); Console.WriteLine(engine.Evaluate("2+2")); // add some code to the current script Console.WriteLine("Add code: var i = 1;"); engine.AddCode("var i = 1;"); // get the object for the script Console.Write("i = "); dynamic obj = engine.Script; // print var i Console.WriteLine(obj.i); // add an app object to the script Console.WriteLine("Add global app object"); engine.Globals.Add("app", new AppObject()); // let the script call the app object Console.Write("Run \"app.writeLine('Hello World!');\": "); engine.Run("app.writeLine('Hello World!');"); }

请注意,在上面的脚本引擎中添加了AppObject。以下是它的定义:

C# [ComVisible(true)] [ClassInterface(ClassInterfaceType.AutoDispatch /* .AutoDual */)] // automatically implements com interface IDispatch ( and IUnknown ) public class AppObject { /// <summary> /// allows scripts to write to the console /// </summary> public void writeLine(string s) { Console.WriteLine(s); } }

请注意,从System.Runtime.InteropServices添加了一些属性。这是必要的,以便.NET创建所需的基础设施,让脚本通过COM/OLE Automation与对象通信。如果没有添加这些,脚本将无法与对象通信,将收到一个错误。

另外,奇怪的是,尽管每个脚本引擎都有自己的全局变量集合,但脚本站点内的所有全局变量共享相同的命名容器。这意味着无论在哪个脚本引擎下创建,每个名称只有一个全局变量被认可。如果两个脚本引擎有相同名称的项目,只有第一个实例将与该名称关联。将对象添加到两个或更多脚本引擎下是没有问题的。这不是设计的方式 - 它是Microsoft Active Script框架设计的一部分。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485