Typedotnet
Run CSharp code, and access to any type/object in .NET 6 and .NET Framework/Mono
Supports (no tested on Mac but should work):
- .NET 6 or superior (called before .NET Core), on Windows/Linux/Mac
- .NET Framework 4.5 or superior on Windows
- Mono on Linux/Mac
Build module
This module was created using @kwruntime/core.
For build:
kwrun build.ts
This will generate an npm
folder with generate js
main file and .d.ts
file declarations
Why?
- For fun
- Win32 stuff, easy to do with .NET Framework (installed on all machines), hard with Node.js (maybe Registry for example)
- Explore .NET 6 (.NET Core)
- Any other solution
Features
- Access any .NET component: Type / Class / Object
- Load dinamycally .NET DLLs
- Call any method, property directly like any function in javascript/typescript
- Access to static members, including Structs, Enums, Generics, etc.
- Compile C# code at run time
- Supports pass javascript objects as
dynamic
(ExpandoObject) to C#.
Differences with edge.js
- Edge execute .NET/Mono/.NET Framework in same process,
typedotnet
create a separated process.
- Due to in-process execution, Edge can be faster in some cases.
typedotnet
allows start many instances of Inter-process comunication, for example running .NET 6 and .NET Framework simultaneously.
typedotnet
can call (almost?) all existing function without compile C# code, Edge needs Methods
with specific signature to call. This means, Edge needs pre-compilation or dynamic compilation, giving some overhead to initialization, with typedotnet
this can be avoided.
typedotnet
doesn't require any native dependency, good for restricted environments or small operations.
How works?
typedotnet
creates another process with .NET Core or .NET Framework/Mono, and comunicate between stdio pipes, using JSON serialization. This makes slower than Edge.js but, also means that is not required native dependencies, nor development environment to install. Also, at least for .NET Core, you can execute on any architecture where can be installed.
typedotnet
can also access to private properties or methods, using the prefix: hidden_
Execute existing methods or accessing to existing types/classes is possible thanks to kodnet project.
typedotnet
exposes a Dotnet
class from what you can do anything:
import {Dotnet} from '@kwruntime/typedotnet'
async function main(){
let dot = new Dotnet()
await dot.start("netcore")
await dot.start("netframework")
}
The idea with typedotnet
is create a "Batch
" execution, and finish after the operations you need do.
import {Dotnet} from '@kwruntime/typedotnet'
async function main(){
let dot = new Dotnet()
await dot.start("netcore")
for(let i=0;i<1000;i++){
await executeSomeOperation()
}
dot.close()
}
async function executeSomeOperation(dot){
let batch = dot.batch()
...
await batch.finish()
}
Access to existing types/classes:
const dot = new Dotnet()
await dot.start("netcore")
const scope = dot.batch()
let sbStatic = scope.static("System.Text.StringBuilder")
let sb = sbStatic.construct()
sb.AppendLine("Línea 1")
sb.AppendLine("Línea 2")
sb.Append("Prueba1,")
sb.Append("Prueba2,")
sb.Append("Prueba3")
sb.AppendLine()
console.info(await scope.wait(sb.ToString()))
console.info(await scope.wait(sb.Length()))
await batch.finish()
Compiling C# code it's possible:
const dot = new Dotnet()
await dot.start("netcore")
let batch = dot.batch()
let startup = await batch.compile({
source: `
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Startup{
public object Invoke(dynamic person){
return new {
Text = "Welcomes from .NET " + (string )person.name + " Your age is: " + person.age.ToString()
};
}
}
`,
typename: "Startup"
})
let person = {
name:"James",
age: 28
}
let result = await batch.wait(startup.Invoke(person))
console.info("Result:", result)
await batch.finish()
If you are only executing void
actions, you need call batch.execute()
instead of batch.wait
for get result.
const dot = new Dotnet()
await dot.start("netcore")
let batch = dot.batch()
...
try{
await batch.execute()
}catch(e){
console.error(e)
console.error(e.dotnetStackTrace)
}
await batch.finish()
You can set properties like any other javascript object. Consider this example similar to compile
example:
const dot = new Dotnet()
await dot.start("netcore")
let batch = dot.batch()
let startup = await batch.compile({
source: `
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public class Person{
public string name {get;set;}
public int age {get;set;}
}
class Startup{
public object Invoke(Person person){
return new {
Text = "Welcomes from .NET " + person.name + " Your age is: " + person.age.ToString()
};
}
}
`,
typename: "Startup"
})
let person = batch.static("Person").construct()
person.name = "James"
person.age = batch.utils.Cast(28, "System.Int32")
let result = await batch.wait(startup.Invoke(person))
console.info("Result:", result)
await batch.finish()
API Reference