11 KiB
| title | sidebar_label | description | pagination_prev | pagination_next |
|---|---|---|---|---|
| Sheets in .NET with Jint | C# + Jint | Process structured data in C#. Seamlessly integrate spreadsheets into your program by pairing Jint and SheetJS. Handle the most complex Excel files without breaking a sweat. | demos/bigdata/index | solutions/input |
import current from '/version.js'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock';
Jint1 is a JavaScript interpreter for .NET Standard and .NET Core. It has
built-in support for binary data with .NET byte[] and ES6 Uint8Array.
SheetJS is a JavaScript library for reading and writing data from spreadsheets.
This demo uses Jint and SheetJS to read and write spreadsheets. We'll explore how to load SheetJS in the Jint engine, exchange binary data with a C# program, and process spreadsheets and structured data.
The "Integration Example" section includes a complete command-line tool for reading arbitrary workbooks and writing data to XLSB (Excel 2007+ Binary Format) workbooks.
Integration Details
:::note pass
Most of the integration functions are not documented. This explanation is based
on version 3.0.0-beta-2051.
:::
The SheetJS Standalone scripts can be parsed and evaluated in a Jint engine instance.
Initialize Jint
A Jint.Engine object can be created in one line:
var engine = new Jint.Engine();
Jint does not expose the NodeJS global but does provide globalThis. Using
Jint.Engine#Evaluate, a global global variable can be created:
The JS code is
global = globalThis;
engine.Evaluate("global = globalThis");
Load SheetJS Scripts
The main library can be loaded by reading the scripts from the file system with
System.IO.File.ReadAllText and evaluating in the Jint engine instance:
/* read and evaluate the shim script */
string src = System.IO.File.ReadAllText("shim.min.js");
engine.Evaluate(src);
/* read and evaluate the main library */
engine.Evaluate(System.IO.File.ReadAllText("xlsx.full.min.js"));
To confirm the library is loaded, XLSX.version can be inspected:
Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));
:::info pass
The Jint Evaluate method returns a generic Jint.Native.JsValue object.
When the JS expression returns a string, the JsValue object is an instance of
Jint.Native.JsString. C# ToString will return the underlying string value.
:::
Reading Files
In C#, System.IO.File.ReadAllBytes reads file data into a byte[] byte array:
string filename = "pres.xlsx";
byte[] buf = File.ReadAllBytes(filename);
Jint natively supports Uint8Array construction from the byte array:
Jint.Native.JsValue u8 = engine.Realm.Intrinsics.Uint8Array.Construct(buf);
Jint.Engine#SetValue will assign the Uint8Array to a scope variable in JS:
engine.SetValue("buf", u8);
The buf variable can be parsed from JS with the SheetJS read method2:
The JS code is
var wb = XLSX.read(buf);
engine.Evaluate("var wb = XLSX.read(buf);");
wb is a SheetJS workbook object. The "SheetJS Data Model" section
describes the object structure and the "API Reference" section
describes various helper functions.
Writing Files
The SheetJS write method3 can write workbooks. The option type: "buffer"
instructs the library to generate Uint8Array objects.
The JS code for exporting to the XLSB format is:
var u8 = XLSX.write(wb, {bookType: 'xlsb', type: 'buffer'});
The file format can be changed with the bookType option4
Jint.Native.JsValue xlsb = engine.Evaluate("XLSX.write(wb, {bookType: 'xlsb', type: 'buffer'})");
xlsb represents a Uint8Array. xlsb.AsUint8Array() returns the bytes as a
byte[] array which can be exported with System.IO.File.WriteAllBytes:
byte[] outfile = xlsb.AsUint8Array();
System.IO.File.WriteAllBytes("SheetJSJint.xlsb", outfile);
Integration Example
:::note
This demo was tested in the following deployments:
| Architecture | Jint Version | Date |
|---|---|---|
darwin-x64 |
3.0.0-beta-2051 |
2023-09-16 |
win10-x64 |
3.0.0-beta-2051 |
2023-09-16 |
:::
- Install .NET5
Platform Configuration
- Set the
DOTNET_CLI_TELEMETRY_OPTOUTenvironment variable to1.
How to disable telemetry (click to hide)
Add the following line to .profile, .bashrc and .zshrc:
export DOTNET_CLI_TELEMETRY_OPTOUT=1
Close and restart the Terminal to load the changes.
Type env in the search bar and select "Edit the system environment variables".
In the new window, click the "Environment Variables..." button.
In the new window, look for the "System variables" section and click "New..."
Set the "Variable name" to DOTNET_CLI_TELEMETRY_OPTOUT and the value to 1.
Click "OK" in each window (3 windows) and restart your computer.
- Open a new Terminal window in macOS or PowerShell window in Windows.
Base Project
- Create a new folder
SheetJSJintand a new project using thedotnettool:
rm -rf SheetJSJint
mkdir SheetJSJint
cd SheetJSJint
dotnet new console --framework net6.0
dotnet run
- Add Jint using the NuGet tool:
dotnet nuget add source https://www.myget.org/F/jint/api/v3/index.json
dotnet add package Jint --version 3.0.0-beta-2051
To verify Jint is installed, replace Program.cs with the following:
var engine = new Jint.Engine();
Console.WriteLine("Hello {0}", engine.Evaluate("'Sheet' + 'JS'"));
After saving, run the program:
dotnet run
The terminal should display Hello SheetJS
Add SheetJS
- Download the standalone script, shim and test file:
- xlsx.full.min.js
- shim.min.js
- pres.xlsx
{\ curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js curl -LO https://sheetjs.com/pres.xlsx}
- Replace
Program.cswith the following:
var engine = new Jint.Engine();
engine.Evaluate("global = globalThis;");
engine.Evaluate(File.ReadAllText("shim.min.js"));
engine.Evaluate(File.ReadAllText("xlsx.full.min.js"));
Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));
After saving, run the program:
dotnet run
The terminal should display SheetJS version {current}
Read and Write Files
- Replace
Program.cswith the following:
using Jint;
/* Initialize Jint */
var engine = new Jint.Engine();
engine.Evaluate("global = globalThis;");
/* Load SheetJS Scripts */
engine.Evaluate(File.ReadAllText("shim.min.js"));
engine.Evaluate(File.ReadAllText("xlsx.full.min.js"));
Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));
/* Read and Parse File */
byte[] filedata = File.ReadAllBytes(args[0]);
Jint.Native.JsValue u8 = engine.Realm.Intrinsics.Uint8Array.Construct(filedata);
engine.SetValue("buf", u8);
engine.Evaluate("var wb = XLSX.read(buf);");
/* Print CSV of first worksheet*/
engine.Evaluate("var ws = wb.Sheets[wb.SheetNames[0]];");
Jint.Native.JsValue csv = engine.Evaluate("XLSX.utils.sheet_to_csv(ws)");
Console.Write(csv);
/* Generate XLSB file and save to SheetJSJint.xlsb */
Jint.Native.JsValue xlsb = engine.Evaluate("XLSX.write(wb, {bookType: 'xlsb', type: 'buffer'})");
File.WriteAllBytes("SheetJSJint.xlsb", xlsb.AsUint8Array());
After saving, run the program and pass the test file name as an argument:
dotnet run pres.xlsx
If successful, the program will print the contents of the first sheet as CSV
rows. It will also create SheetJSJint.xlsb which can be opened in Excel or
another spreadsheet editor.
:::caution pass
If the using Jint; directive is omitted, the build will fail:
'JsValue' does not contain a definition for 'AsUint8Array' and no accessible extension method 'AsUint8Array' accepting a first argument of type 'JsValue' could be found
:::
Standalone Application
- Find the runtime identifier (RID) for your platform6. The RID values for tested platforms are listed below:
| Platform | RID |
|---|---|
| Intel Mac | osx-x64 |
| Windows 10 (x64) | win10-x64 |
- Build the standalone application. Replace
$RIDwith the real value in:
dotnet publish -c Release -r $RID --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
Tested platforms (click to hide)
For Intel Mac, the RID is osx-x64 and the command is
dotnet publish -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
For Windows 10 x64, the RID is win10-x64 and the command is:
dotnet publish -c Release -r win10-x64 --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true
- Copy the generated executable to the project directory.
The build from step 9 is placed in bin\Release\net6.0\$RID\publish and the
binary name will be SheetJSJint or SheetJSJint.exe depending on OS.
Tested platforms (click to hide)
For Intel Mac, the RID is osx-x64 and the command is:
cp bin/Release/net6.0/osx-x64/publish/SheetJSJint .
For Windows 10 x64, the RID is win10-x64 and the command is:
copy .\bin\Release\net6.0\win10-x64\publish\SheetJSJint.exe .
- Run the generated command.
./SheetJSJint pres.xlsx
.\SheetJSJint pres.xlsx
-
The Jint project recommends the "MyGet" service. According to the developers, the "NuGet" package is "occasionally published". ↩︎
-
See "Supported Output Formats" in "Writing Files" for details on
bookType↩︎ -
At the time of writing, https://dotnet.microsoft.com/en-us/download is the official endpoint. ↩︎
-
See ".NET RID Catalog" in the .NET documentation ↩︎