Running JavaScript in. NET applications

Running JavaScript in. NET applications

I was working on a side job the other day and realized that I needed to use some JavaScript functions.

最后更新 5/11/2022 6:51 AM
liamwang 精致码农
预计阅读 10 分钟
分类
.NET
标签
.NET C#

I was working on a side job the other day and realized that I needed to use some JavaScript functions. The thought of dealing with Node.js and npm again gave up completely, so I decided to explore the possibility of running JavaScript in. NET applications. Crazy, huh? In fact, it's surprisingly simple.

1. Why are you doing this?

As much as I like the. NET ecosystem, there are some things that the JavaScript ecosystem does better. One of them is that you can find a library for everything, especially when it comes to the Internet.

以语法高亮为例。这可以直接用 C# 来做,但这不是一个特别流畅的体验。例如,TextMateSharp 项目为 TextMate 语法提供了一个解释器。这些文件是 VS Code 用来为一种语言添加基本语法高亮的。然而,如果你想部署应用程序,它包装了一个本地依赖,这就增加了一些复杂性。

相比之下,JavaScript 有大量成熟的语法高亮库。仅举几例,有 highlight.jsPrism.js(在本博客中使用)和 shiki.js。尤其是前两个,非常成熟,有多个插件和主题,而且有简单的 API。

As a. NET developer, the obvious problem with JavaScript is that you need to learn and choose to enter a complete chain of independent tools that work with Node.js and NPM. This seems like a big overhead just to use a small feature.

As a result, we are in a dilemma. We either go the C#(+ Native) route or we have to switch to JavaScript.

Or... We call JavaScript directly from our. NET application🤯

2. Running JavaScript in. NET

Once you decide to run JavaScript in your. NET code, you will consider several options. You can borrow a JavaScript engine and let it run your JavaScript for you, but you haven't really solved the problem, you still need to install Node.js.

Another option is to bundle the JavaScript engine directly in your library. This is not as crazy as it sounds, and several NuGet packages take this approach and then expose a C#layer to interact with the engine.

Below is a list of some packages you can use.

Jering.JavaScript.NodeJS

这个库采取了上述的第一种方法。它不包括包中的 Node.js。相反,它为执行 JavaScript 代码提供了一个 C# API,并调用了安装在你机器上的 Node.js。这在你知道两者都已安装的环境中可能很有用,但它并没有真正解决我想避免的问题。

ChakraCore

ChakraCore 是 Edge 转为基于 Chromium 引擎之前最初使用的 JavaScript 引擎。根据 GitHub 项目的介绍:

ChakraCore 是一个带有 C 语言 API 的 JavaScript 引擎,你可以用它来为任何 C 语言或 C 语言兼容项目添加对 JavaScript 的支持。它可以在 Linux macOS 和 Windows 上针对 x64 处理器进行编译。而 x86 和 ARM 只适用于 Windows。

因此,ChakraCore 包括一个本地依赖,但由于 C# 可以 P/Invoke 到本地库,这本身并不是一个问题。但它会带来一些部署方面的挑战。

ClearScript (V8)

Node.JS、Chromium、Chrome 和最新的 Edge 使用的都是 V8 JavaScript 引擎。Microsoft.ClearScript 包为该库提供了一个封装,为调用 V8 库提供了一个 C# 接口。就像 ChakraCore 一样,V8 引擎本身是一个本地依赖。ClearScript 库负责 P/Invoke 调用,提供了一个很好的 C# API,但你仍然要确保你在目标平台上部署了正确的本地库。

Jint

Jint 很有意思,因为它是一个完全在 .NET 中运行的 JavaScript 解释器,没有任何本地的依赖!它完全支持 ECMAScript 5.1 (ES5),并支持 .NET Standard 2.0,所以你可以在你的所有项目中使用它!

Jurassic

Jurassic 是另一个 JavaScript 引擎的 .NET 实现,类似于 Jint。也和 Jint 类似,它支持所有的 ES5,而且似乎也部分支持 ES6。与 Jint 不同的是,Jurassic 不是一个解释器,它将 JavaScript 编译成 IL,这使得它的速度非常快,而且它没有本地的依赖性。

So, of all these options, which one should you choose?

3 JavaScriptEngineSwitcher: When a JS engine is not enough

There is also a great project that allows you to simply try any of the libraries above. Although all libraries allow you to run JavaScript, they all have slightly different C#APIs to interact with. This can make comparing them a little painful because you have to learn different APIs for each library.

JavaScriptEngineSwitcher 这个库为我提到的所有库和更多的库提供了封装:

Each library is in a separate package (engines with local dependencies require an additional local package), and there is also a Core package that provides common APIs. Even if you don't plan to switch JS engines, I tend to use the JavaScriptEngineSwitcher wrapper library whenever possible so you don't have to figure out a new API later when you need to switch engines.

在 .NET 项目中改变使用的 JavaScript 引擎在我看来是完全可能的。例如,我开始使用 Jint,但当我需要执行更大的脚本时,我遇到了性能问题,于是换成了 JurassicJavaScriptEngineSwitcher 让这一切变得很简单,只需在我的项目中添加一个新的包并改变一些初始化代码即可。

我最近才发现 JavaScriptEngineSwitcher 这个库,但最新版本的下载量已接近一百万,它被用于 .NET 静态网站建设者 Statiq 中。在这篇文章的最后部分,我将举一个最基本用法的例子。

4 Example: Using JavaScriptEngineSwitcher to run prism.js in a console application

在这篇文章的开头,我讨论了一个特定的场景--代码块的语法高亮。在本节中,我将展示如何使用 prism.js 高亮一小段代码,并在一个控制台应用程序中运行。

开始之前请添加 JavaScriptEngineSwitcher.Jurassic NuGet 包的引用。

dotnet add package JavaScriptEngineSwitcher.Jurassic

接下来,下载你想运行的 JavaScript 文件。例如,我从 Prism.js 的官网下载了 prism.js 文件,并将 C# 添加到默认支持高亮的语言集。在把文件放到项目文件夹的根目录后,我把文件更新为嵌入资源。你可以在你的 IDE 中操作,也可以手动编辑项目文件:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="JavaScriptEngineSwitcher.Jurassic" Version="3.17.4" />
  </ItemGroup>

  <!-- 👇 Make prism.js an embedded resource -->
  <ItemGroup>
    <None Remove="prism.js" />
    <EmbeddedResource Include="prism.js" />
  </ItemGroup>

</Project>

剩下的就是编写代码,在我们的程序中运行脚本。下面的代码段设置了 JavaScript 引擎,从程序集中加载嵌入的 prism.js 库,并执行它。

using JavaScriptEngineSwitcher.Jurassic;

// Create an instance of the JavaScript engine
IJsEngine engine = new JurassicJsEngine();

// Execute the embedded resource called JsInDotnet.prism.js from the provided assembly
engine.ExecuteResource("JsInDotnet.prism.js", typeof(Program).Assembly);

现在我们可以在同一个上下文中运行我们自己的 JavaScript 命令。我们可以通过使用 SetVariableNameExecuteEvaluate 从 C# 向 JavaScript 引擎传递数值:

// This is the code we want to highlight
string code = @"
using System;

public class Test : ITest
{
    public int ID { get; set; }
    public string Name { get; set; }
}";

// set the JavaScript variable called "input" to the value of the c# variable "code"
engine.SetVariableValue("input", code);

// set the JavaScript variable called "lang" to the string "csharp"
engine.SetVariableValue("lang", "csharp");

// run the Prism.highlight() function, and set the result to the "highlighed" variable
engine.Execute($"highlighted = Prism.highlight(input, Prism.languages.csharp, lang)");

// "extract the value of "highlighted" from JavaScript to C#
string result = engine.Evaluate<string>("highlighted");

Console.WriteLine(result);

When you put them together and run them, the highlighted code is printed to the console:

<span class="token keyword">using</span>
<span class="token namespace">System</span
><span class="token punctuation">;</span>

<span class="token keyword">public</span>
<span class="token keyword">class</span>
<span class="token class-name">Test</span>
<span class="token punctuation">:</span>
<span class="token type-list"><span class="token class-name">ITest</span></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span>
<span class="token return-type class-name"
  ><span class="token keyword">int</span></span
>
ID <span class="token punctuation">{</span>
<span class="token keyword">get</span><span class="token punctuation">;</span>
<span class="token keyword">set</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span>
<span class="token return-type class-name"
  ><span class="token keyword">string</span></span
>
Name <span class="token punctuation">{</span>
<span class="token keyword">get</span><span class="token punctuation">;</span>
<span class="token keyword">set</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>

After rendering, it looks like this:

我对整个过程的简单程度感到惊讶。启动一个 JavaScript 引擎,加载 prism.js 文件,并执行我们的自定义代码是如此顺利。这是我面临问题的完美解决方案。

我显然不建议所有的应用程序都这样做。如果你需要运行大量的 JavaScript,那么直接使用 Node.js 生态系统及工具可能更容易。但如果你只是想利用一个小型的、独立的工具(如 prims.js),那么这是一个不错的选择。

5 summarizes

在这篇文章中,我展示了如何使用 JavaScriptEngineSwitcher NuGet 包来在 .NET 应用程序中运行 JavaScript。这个包为许多不同的 JavaScript 引擎提供了一个一致的接口。其中一些引擎(如 Chakra CoreV8)需依赖一个本地组件,而其他引擎(如 JintJurassic)只使用托管代码。最后,我展示了你如何使用 JavaScriptEngineSwitcher 在 .NET 应用程序内部运行 Prims.js 代码高亮库。

Original: andrewlock.net/running-javascript-in-a-dotnet-app-with-javascriptengineswitcher/

Author: Andrew Lock

Translation: Exquisite Code Farmer

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 4/22/2026

Support for. NET by operating system versions (250707 update)

Use virtual machines and test machines to test the support of each version of the operating system for. NET. After installing the operating system, it is passed by measuring the corresponding running time of the installation and being able to run the Stardust Agent.

继续阅读
同分类 / 同标签 2/7/2026

Summary of experience in using AOT

From the very beginning of project creation, you should develop a good habit of conducting AOT release testing in a timely manner whenever new features are added or newer syntax is used.

继续阅读