javascript – Using .Net classes in TypeScript

Question:

There is an idea to have access from TypeScript to methods and properties of .Net classes.

I have experience calling methods of .Net objects from native https://habrahabr.ru/users/serginio1/topics/

And in particular Cross-platform use of .Net classes from unmanaged code. Or analogue of IDispatch on Linux

There is an idea to call through Native Client Messaging System

There we have JavaScript and native interaction through messages

In JavaScript, we can subscribe to events

function handleMessage(message) {
  // In the example, we simply log the data that's received in the message.
  var logEl = document.getElementById('log');
  logEl.textContent += message.data;
}

And send messages

var dictionary = {
  key:guid,
  MethodName: name,
  param_array: args
}
nacl_module.postMessage(dictionary);

On the native side

You can receive messages

virtual void HandleMessage(const pp::Var& var) {
  if (var.is_dictionary()) {
    pp::VarDictionary dictionary(var);
    // Use the dictionary
    pp::VarArray keys = dictionary.GetKeys();
    // ...
  } else {
    // ...
  }
}

So send it

pp::VarDictionary dictionary;
dictionary.Set(pp::Var("command"), pp::Var(next_command));
dictionary.Set(pp::Var("param_int"), pp::Var(123));
pp::VarArray an_array;
an_array.Set(0, pp::Var("string0"));
an_array.Set(1, pp::Var("string1"))
dictionary.Set(pp::Var("param_array"), an_array);
PostMessage(dictionary);

All this can be done through Proxy

class NetWrapper{

    public currentCount: any;

    public static dictionary = {};

    public proxy: any;

    public static wm = new WeakMap(); // Слабые ссылки на объекты
    public static refArray = new Array<int>(); // ссылки на .Net объекты   
    constructor(private netRef:int) { this.SetProxy(); }


     private GetPromise(name: PropertyKey,args)
    {

        let key = Guid.newGuid();
        let promise = new Promise((resolve, reject) => {
            let item = new Item(resolve, args, name);
            this.dictionary[key] = item;

           var dictionary = {
           netRef:netRef,
           key:key,
           MethodName: name,
           param_array: args
         }
          nacl_module.postMessage(dictionary);
        });


        return promise;
    }


    private SetProxy(): void {

        let self=this;
        this.proxy = new Proxy({}, {

            get: function(rcvr: any, name: PropertyKey)
            {

               // Проблемы с определением, что свойство возвращает ссылку на метод
               // поэтому будем вызвать все как методы
               // if (этоСвойство)
               //     return self.GetPromise(name, []);

               return (...args) => {
                   return self.GetPromise(name,args)

                };


            }


        });
    }




// Пример вызова метода .Net

function handleMessage(message) {
  // In the example, we simply log the data that's received in the message.
  let data=message.data;
  let result=data.result;
  let item = <Item>this.dictionary[data.key];

  delete this.dictionary[key];

  if (data.resultIsObject)
   {

    let ref=<int>result;
    result=new NetWrapper(ref);
    refArray.push(ref);
    wm.set(result,ref);
  }

  item.resolve(result);

}

Since there are no finalizers in JavaScript, we can use WeakMap

That is, it would be possible to unload the values ​​from wm and compare them with the current refArray. If there are no links in WeakMap, then you can release links on the .Net side

But it seems like

Because references are weak, WeakMap's keys are not enumerable (that is, there is no method that returns a list of keys). Otherwise the list would depend on the garbage collection state, introducing indeterminism. If you want to have a list of keys, you must maintain it yourself.

Usage is

  let HttpClient=await NetWrap.GetType("System.Net.Http.HttpClient","System.Net.Http.dll");
     let HttpClientHandler = await NetWrap.GetType("System.Net.Http.HttpClientHandler","System.Net.Http.dll");

    let client=await NetWrap.new(HttpClient);
    let responst= await (await client.GetStringAsync("https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx")).Result();
 //Result вызываем как функцию

It is possible for asynchronous result methods inside Net to be made asynchronous

I will be glad to any advice. And maybe no one needs it and you shouldn’t write to the table at all?

True, I found a link to the finalizer feature https://www.npmjs.com/package/finalize

var finalize = require('finalize');
 
var obj = { x: 1337 };
finalize(obj, function () {
  console.log(this.x); // this will print '1337' 
});
global.gc();
// nothing will happen, var obj above holds obj alive 
obj = null;
global.gc();
// the previous line should trigger the callback above 

In addition, cef / JavaScriptIntegration was given to me for integration

You can do without the asynchrony of calling ordinary methods.

At the same time, you can register various handlers for asynchronous methods, for events

As a result, you can call asynchronous methods, for example, by adding the async keyword, and for properties, you can use @ at the beginning of the property

let url= "https://msdn.microsoft.com/ru-ru/library/hh551745(v=vs.118).aspx");
let response= await client.async.GetStringAsync(url);
let response= client.GetStringAsync(url).@Result;

Answer:

Made and works on Angular 2 and TypeScript

let Net = NetObject.NetWrapper;

let del = NetObject.FlagDeleteObject;
//let SB = Net.Новый("System.Text.StringBuilder");
let StringBuilder = Net.Тип("System.Text.StringBuilder");
let SB = new StringBuilder();
this.AddComment("SB", SB);
var res = SB.Append("Первая строка");
res(del);

var ToStr = SB.ToString();
this.AddComment("Tostring=", ToStr);

SB.Capacity=40;

res = SB._Capacity;
this.AddComment("_Capacity=", res);
SB(del);
let Тестовый = Net.Тип("TestDllForCoreClr.Тестовый", "TestDllForCoreClr");
var TO = new Тестовый("Свойство из Конструктора");
 var resAsync = await TO.async.GetStringAsync();

this.ResultExecute.push(new ResTest("GetStringAsync", resAsync));

res = TO.ДженерикМетод(1, 2, 5);
this.AddComment("ДженерикМетод с выводом типов ", res);

let Int32 = Net.GetType("System.Int32");

res = TO.ДженерикМетод([Int32, Int32], 1, 2, 5);
this.AddComment("ДженерикМетод с аргeментами типов ", res);


var Dictionary2 = Net.GetType("System.Collections.Generic.Dictionary`2", "System.Collections");
var DyctionaryIS = Net.GetGenericType(Dictionary2, "System.Int32", "System.String");
var D = new DyctionaryIS();

res = TO.ДженерикМетод2(D, 99, "Hello");

this.AddComment("ДженерикМетод2 с выводом типов ", res);

res = TO.ДженерикМетод2([Int32, "System.String"],D, 99, "Hello");
this.AddComment("ДженерикМетод2 с аргументами ", res);

var task = TO.GetStringAsync();
res = await Net.async.ReturnParam(task);


this.AddComment("выполнение полученной задачи асинхронно ", res);

var array = Net.GetNetArray(1, "Привет", 4.4);

for (let item of array)
    this.AddComment("Элемент ", item);




var EO = TO.ПолучитьExpandoObject();
this.AddComment("Свойство ExpandoObject Имя ",EO._Имя);
this.AddComment("Свойство ExpandoObject Число ", EO._Число);

var делегат = EO._ВСтроку;
this.AddComment("Результат вызова  делегата Встроку ", делегат());
this.AddComment("Результат вызова  как Метода ", EO.ВСтроку());

NetObject.DeleteNetObjets(Int32, task, D, DyctionaryIS, Dictionary2, TO, Тестовый, StringBuilder, array, EO, делегат);
this.AddComment("Количество элементов в хранилище ", Net.КоличествоЭлементовВХранилище());
this.AddComment("Первый удаленный ", Net.FirstDeleted());

The difference from C# is To get the property you need to add "_"

res = SB._Capacity;

To call an asynchronous method, add the async keyword

var resAsync = await TO.async.GetStringAsync();

To call a generic method, if it is impossible to infer types by parameters, then specify the arguments in an array

res = TO.ДженерикМетод2([Int32, "System.String"],D, 99, "Hello"); 

Support for events and passing JS objects will be added later. I will be glad to any suggestions and criticism. What are the best examples for an article?

As a result, I posted an article with examples of CEF, ES6, Angular 2, TypeScript using .Net Core classes to extend capabilities

And more CEF, Angular 2 using .Net Core class events

And more CEF, ES6, Angular 2, WebPack 2 .Net Core desktop app without backend

Scroll to Top