Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jameschch/Blazor.DynamicJavascriptRuntime.Evaluator

Execute dynamic object expressions as Javascript in Blazor
https://github.com/jameschch/Blazor.DynamicJavascriptRuntime.Evaluator

blazor dynamic javascript jsinterop razor wasm webassembly

Last synced: 10 days ago
JSON representation

Execute dynamic object expressions as Javascript in Blazor

Awesome Lists containing this project

README

        

# Blazor.DynamicJavascriptRuntime.Evaluator (A.K.A. Gasmask)

Wouldn't it be really useful if you could run a line or two of Javascript in your Blazor C# app?
Wouldn't it be handy if you could execute arbitrary Javascript at runtime without strings of script?
Wouldn't it be a big plus if the Javascript code was declared as a dynamic object expression and could be exposed to unit tests?
Wouldn't it be nice if you could consume Javascript library API's without creating interop wrappers?

Calling Javascript dynamically from C# couldn't be easier:

```csharp
var context = (new EvalContext(JSRuntimeInstance) as dynamic).window.location = "www.github.com";
await (context as EvalContext).InvokeAsync();
//window.location = "www.github.com";
```

...or with alternate syntax:

```csharp
using (dynamic context = new EvalContext(JSRuntimeInstance))
{
(context as EvalContext).Expression = () => context.window.location = "www.github.com";
//window.location = "www.github.com";
}
```

When it comes to executing code with arguments, the C# parser will support this:

```csharp
using (dynamic context = new EvalContext(JSRuntimeInstance))
{
dynamic arg = new EvalContext(JSRuntimeInstance);
dynamic arg2 = new EvalContext(JSRuntimeInstance);
(context as EvalContext).Expression = () => context.Chart.config.data.datasets[arg.i].data.push(arg2.config.data.datasets[arg.i].data);
//Chart.config.data.datasets[i].data.push(config.data.datasets[i].data);
}
```

Need to call some script that returns a value? No problem:

```csharp
dynamic context = new EvalContext(runtime.Object);
(context as EvalContext).Expression = () => context.document.cookie;
var cookie = await (context as EvalContext).InvokeAsync();
//document.cookie
```

In order to satisfy the C# parser, an underscore ("_") can stand in for a space character in Javascript. This is disabled by default and you can configure your space placeholder:

```csharp
using (dynamic context = new EvalContext(JSRuntimeInstance))
{
var settings = new EvalContextSettings { EnableSpaceCharacterPlaceholderReplacement = true, SpaceCharacterPlaceholder = "_" };
dynamic arg = new EvalContext(JSRuntimeInstance, settings);
(context as EvalContext).Expression = () => context.var_instance = arg.new_object();
//var instance = new object();
}
```

The dynamic expression is eagerly evaluated. This means decimal arithmetic will not be mangled by Javascript:

```csharp
using (dynamic context = new EvalContext(JSRuntimeInstance))
{
(context as EvalContext).Expression = () => context.sum = 0.1M + 0.2M * 0.5M / 0.5M;
//sum = 0.3;
}
```

Maybe you feel like a bit of JQuery?

```csharp
using (dynamic context = new EvalContext(JsRuntime))
{
(context as EvalContext).Expression = () => context.jQuery("body").css("overflow-y", "hidden");
//jQuery("body").css("overflow-y", "hidden")
}
```
Sorry, no $ allowed.

How about passing complex types as arguments? We've got you covered for anonymous types:

```csharp
using (dynamic context = new EvalContext(JsRuntime))
{
var arg = new { Property = "Value", Field = 123, Child = new { Member = new DateTime(2001, 1, 1) } };
(context as EvalContext).Expression = () => context.myScript.set(arg);
//myScript.set({"property":"Value","field":123,"child":{"member":"2001-01-01T00:00:00"}})
}
```

Passing user-defined types takes more effort, but not too much:

```csharp
var settings = new EvalContextSettings();
settings.SerializableTypes.Add(typeof(Specified));
using (dynamic context = new EvalContext(JsRuntime, settings))
{
var arg = new Specified { Member = "abc" };
(context as EvalContext).Expression = () => context.myScript.setSpecified(arg);
//myScript.setSpecified({"member":"abc"})
}
```

The execution of Javascript is performed with the eval() function, so it's imperative to sanitize user input that's passed into the Javascript runtime. You have been warned.

## Setup

First, install from nuget:

```
Install-Package DynamicJavascriptRuntime.Blazor.Evaluator
```

[https://www.nuget.org/packages/DynamicJavascriptRuntime.Blazor.Evaluator/](https://www.nuget.org/packages/DynamicJavascriptRuntime.Blazor.Evaluator/)

You then need to add a script include to your index.htm:

```html

```

## Syntax

The are a few different syntax options for dynamic expressions:

- The ```using``` blocks wrapping the EvalContext are optional but prevent forgotten calls to Invoke.
- Setting the ```Expression``` property is optional. You can chain an expression directly on the EvalContext e.g.:
```csharp
dynamic context = new EvalContext();
context.alert("Gasmask");
await (context as EvalContext).InvokeVoidAsync()
```
- You can chain multiple javascript calls on separate lines with a single EvalContext. This makes sense for some "fluent" libraries like jQuery.