从.NET应用程序引用Google的V8引擎

35

我正在构建一个.NET 3.5应用程序,并需要在服务器上评估JS代码-基本上是用户提供的规则集,可在浏览器中或在服务器上运行。托管JS不是选项,因为JS代码将在运行时提供。 Aptana的Jaxer也不是选项。因此,我正在研究在我的应用程序中使用V8引擎的版本。

我成功地将源代码构建为DLL,但该DLL既不是托管库,也不是COM。 V8只是纯C ++。

有什么想法可以在C#中与这种类型的DLL进行交互吗?另外,我也可以考虑其他建议,如SpiderMonkey或其他JS引擎。

先感谢您的回答。

更新:

我能够使用Ryan的解决方案。我只需更新来自trunk的最新版本的构建的引用。它非常好用。谢谢Ryan。


另外,我可以在哪里获取已编译的 DLL 呢?(因为我太懒得自己编译,主要是因为我没有设置 C++ 的 VS) - Jason Bunting
我已经更新了我的帖子,并附上了下载我创建的测试项目的链接。 - Ryan Cook
对于那些刚发现这个页面的人,现在在Codeplex上也有V8.NET。 - James Wilkins
1
http://v8dotnet.codeplex.com/ 在 Codeplex 上的 V8.NET - rahulroy9202
V8.Net现已支持.Net Standard,并可在NuGet上获取! :) (https://www.nuget.org/packages/V8.Net/) - James Wilkins
9个回答

35

我意识到这可能不是您问题的确切答案,但我想说一下我的看法,因为我怀疑很少有人尝试过这样做。

我通过使用混合模式C++创建了一个托管包装器。还有其他方法可以做到这一点,但我打算尝试制作一个完整的包装器,可从任何.NET语言中使用。

让库以这种方式编译,使其可以包含在混合模式项目中,有点具有挑战性。我必须修改运行时库(在SConstruct文件中)的用法,将其用于/MD和/MDd,以使其与/clr开关兼容。

到目前为止,我只运行了简单的脚本,因为我还没有实现回调、自定义方法、对象等。

以下是我一个测试应用程序的用法快速示例:

V8DotNet.Shell shell = new V8DotNet.Shell();

shell.ExecuteScript(@"print('V8 version is: ' + version());");

它可以很好地运行像base64编码器之类的复杂脚本。但目前我只能从c++端添加自定义项。

如果有人感兴趣,我愿意提供更多信息和代码,因为我可能永远不会再接着做这个项目了。但是,恐怕这太多的代码不能在这里发布,所以我们需要找到其他媒介,如google code或codePlex。

编辑:


好的,我已经上传了代码。我必须放置一个免责声明:该项目还处于非常早期的阶段,我最多只是一个C++业余爱好者,所以不要对它抱太大的希望。此外,该项目是在chrome发布后创建/完成的,因此包含的v8版本可能已经过时了。

话虽如此,这就是它:http://ryanscook.com/Files/V8-DotNet.zip(21.5 MB)

在软件包中,你会发现以下有趣的项目:

V8Net-Library\V8.Net\V8.Net.sln- 这是具有托管C++包装器 proj 和用于测试的 C# 控制台应用程序的解决方案。

Dependencies\V8- 这是我用来构建 V8 lib 的 V8 代码。

希望对你有所帮助!


我不得不修改运行时库(在SConstruct文件中)以使用/MD和/MDd,以便与/clr开关兼容。这并不是一个非常困难的挑战! :) - leppie
7
找出需要做的事情是关键。打字总是最容易的部分。我猜我的C++经验不足加剧了一些挫败感。 - Ryan Cook
Ryan:感谢您的帮助。我想使用/clr开关进行构建,就像您所做的那样。我对Scons毫无经验。能否详细告诉我您对SConstruct文件所做的更改?特别是,您在哪里指定了/clr开关。此外,看起来对于共享库,已经使用了/MD。提前感谢您的帮助。 - NathanD
说实话,我记不清我的v8构建的确切细节了。/clr在包装库中。基本上,我必须创建一个稍微修改过的v8.lib,以便将其链接到我的混合模式dll。我会尽力找时间今天在某个地方发布这些项目供您下载。 - Ryan Cook
1
Ryan:请看我上面的更新。你的代码在最新的主干版本中运行良好。谢谢。 - NathanD
显示剩余2条评论

18
您可以尝试使用Javascript .NET: http://javascriptdotnet.codeplex.com/ 它可以让您从.NET创建V8上下文,并在其中注册CLI对象,以便您可以操纵它们并从Javascript代码中调用成员。它会在运行时编译Javascript。
去看看吧。

1
true,非常酷,但是非常不适合服务器端使用...因为V8引擎不是线程安全的。(参见:http://javascriptdotnet.codeplex.com/workitem/7062)这真是令人失望。 - Davy Landman
1
javascriptdotnet 现在是线程安全的。可以同时运行多个 v8 实例(隔离),但它们无法相互交互。 - Oliver Bock

13

请查看v8sharp。它支持在.NET应用程序内执行JS。它还允许您向v8引擎注册.NET类型,以便您的JS代码可以与您的.NET代码交互。我正在添加对挂钩函数/委托支持的支持。


v8sharp很棒,我在我的项目中使用过。 - guaike

1
你也可以尝试使用 V8.NET。

https://www.nuget.org/packages/V8.Net/

它允许您在比许多其他包装器更低的级别上轻松地将代码与V8集成。它还支持.Net 4.6.1+和.Net Standard 2.0+(.Net Core)。

1

是的,我之前听说过JS DLR实现,所以我首先研究了一下。但不幸的是,微软似乎还没有发布JS的任何东西,只有IronPython。真遗憾。 - NathanD
1
托管在DLR上的JavaScript已经死了。请参考这个答案:http://code.google.com/apis/v8/design.html - James Hugard
1
我不理解V8设计文档与DLR上的Javascript有任何关系?DLR上的Javascript的重点不仅仅是纯速度(尽管这将是一个很好的奖励),而且要与现有的.NET生态系统进行清洁的互操作,而这是V8所不能做到的。 - Orion Edwards

1

由于这个问题是一段时间以前发布的,所以我想提供一些更新。

微软已经制作了ClearScript脚本引擎,支持V8、JScript和VBScript。

您可以轻松添加C#类型,例如控制台,并在脚本中使用它。 添加WPF按钮类型并创建一个也没有问题。在GitHub上有一些很好的例子,我建议任何阅读此文的人快速浏览一下。


0

0

据我所知,使用IJW(Managed C++)编译它应该可以正常工作 - 但我可能非常错误,因为我从未接触过MC++。


0

代码复活。
根据2018年以及.NET Core 2.0+
您可以使用vroomjs-core

执行一些Javascript:

using (var engine = new JsEngine())
{
    using (var context = engine.CreateContext())
    {
        var x = (double)context.Execute("3.14159+2.71828");
        Console.WriteLine(x);  // prints 5.85987
    }
}

创建并返回一个Javascript对象,然后调用它的一个方法:
using (JsEngine js = new JsEngine(4, 32))
{
    using (JsContext context = js.CreateContext())
    {
        // Create a global variable on the JS side.
        context.Execute("var x = {'answer':42, 'tellme':function (x) { return x+' '+this.answer; }}");
        // Get it and use "dynamic" to tell the compiler to use runtime binding.
        dynamic x = context.GetVariable("x");
        // Call the method and print the result. This will print:
        // "What is the answer to ...? 42"
        Console.WriteLine(x.tellme("What is the answer to ...?"));
    }
}

从Javascript访问CLR对象的属性和方法:

class Test
{
    public int Value { get; set; }
    public void PrintValue(string msg)
    {
        Console.WriteLine(msg+" "+Value);
    }
}

using (JsEngine js = new JsEngine(4, 32))
{
    using (JsContext context = js.CreateContext())
    {
        context.SetVariable("m", new Test());
        // Sets the property from Javascript.
        context.Execute("m.Value = 42");
        // Call a method on the CLR object from Javascript. This prints:
        // "And the answer is (again!): 42"
        context.Execute("m.PrintValue('And the answer is (again!):')");
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接