---
title: "Call a JavaScript function from C#"
url: https://recursiveai.org/oneecma/cookbook/call-javascript-function/
description: "Call a JavaScript function from C#: load a script, get the function, pass arguments and read the result, with errors caught as .NET exceptions. A complete program with an embedded engine."
version: "1.0.0"
---

# Call a JavaScript function from C#

Evaluate the script that defines the function, read the function from the global object with `GetProperty`, and call it with `engine.Call`. The program below calls a pricing function from a script with C# arguments.

```shell
dotnet new console -o CallJs && cd CallJs
dotnet add package RecursiveAI.OneEcma --version 1.0.0
```

Put this in `Program.cs` and run `dotnet run`:

```csharp
using RecursiveAI.OneEcma;

var engine = new ScriptEngine();
engine.Evaluate("""
    function price(qty, unit, code) {
      if (qty <= 0) throw new RangeError(`qty must be positive, got ${qty}`);
      const discount = code === "SPRING" ? 0.1 : 0;
      return Math.round(qty * unit * (1 - discount) * 100) / 100;
    }
    """, "pricing.js");

JsValue price = engine.GetProperty(engine.Global, "price");

JsValue a = engine.Call(price, default,
    [JsValue.FromNumber(12), JsValue.FromNumber(2.5), JsValue.FromString("SPRING")]);
JsValue b = engine.Call(price, default,
    [JsValue.FromNumber(3), JsValue.FromNumber(9.99), JsValue.FromString("")]);
Console.WriteLine($"{a.AsNumber} and {b.AsNumber}");

try
{
    engine.Call(price, default,
        [JsValue.FromNumber(0), JsValue.FromNumber(1), JsValue.FromString("")]);
}
catch (JsException e)   // what the script threw, as a .NET exception
{
    Console.WriteLine(e.Message);
}
```

```text
27 and 29.97
RangeError: qty must be positive, got 0
```

`default` is the `this` value, here `undefined`. Arguments are `JsValue`s: `FromNumber`, `FromString`, `FromBoolean` and `FromObject` make them. An exception thrown in the script comes back as a `JsException` with the script’s message, and `e.Report` holds a [full report](https://recursiveai.org/oneecma/cookbook/error-reports/) with the line that threw.

## Calling it many times

Evaluate the script once and keep the engine and the function: each `Call` runs only the function. Pass a `CancellationToken` as the last argument of `Call` to stop a call that takes too long, or set [limits](https://recursiveai.org/oneecma/cookbook/sandbox/) on the engine.

## Limits

- **One engine per thread.** Calls into the same engine must come from one thread at a time.
- **Async functions return a promise.** Call `engine.RunJobs()` to run pending jobs, then read the promise with `engine.MainRealm.AsPromise(value)`.
- **Modules:** a function exported from an ES module isn’t on the global object. Load modules with `EvaluateModule` and a host that resolves them ([Runtime and the host](https://recursiveai.org/oneecma/docs/runtime/)).

To run a script and read its result without a function, see [Run JavaScript in C#](https://recursiveai.org/oneecma/cookbook/run-javascript/). To go the other way, see [Call C# from JavaScript](https://recursiveai.org/oneecma/cookbook/host-functions/).
