CEF, ES6, Angular 2, TypeScript использование классов .Net Core. Создание кроссплатформенного GUI для .Net с помощью CEF

    Меня все спрашивают — «Зачем это нужно?». На что, я гордо отвечаю — «Я в 1С использую для доступа к торговому оборудованию, к Вэб-сервисам по ws-протоколам, готовым компонентам. 1С, Linux, Excel, Word, OpenXML,ADO и Net Core. Кроме того, сделаю передачу JS объектов на сторону .Net с использованием через DynamicObject.

    Можно сделать определенную конфигурацию CEF для всех платформ и можно делать кросспалатформенные декстопные приложения. Как аналог Electron. .Net Core развивается и можно достаточно легко перевести приложения под WPF и UWP на Angular 2» сделав описание классов и использовать IntelliSense при кодировании на TypeScript.

    Но я прекрасно понимаю, что это всего лишь высокопарные слова, и мало кому это нужно. Но мне чертовски интересно, особенно после программирования на 1С.

    Для показа возможностей, возьму пример из моей статьи Кроссплатформенное использование классов .Net в 1С через Native ВК. Или замена COM на Linux II.

    В нем куча сахара и показывает все проблемы. Сразу прошу прощения за Руслиш. Я очень стараюсь, но у меня на нем куча примеров, а времени очень мало.

     // Метод расширения
        //IConfiguration WithDefaultLoader(this IConfiguration configuration, Action<LoaderSetup> setup = null, IEnumerable<IRequester> requesters = null);
        var config = Configuration.Default.WithDefaultLoader();
        // Устанавливаем адрес страницы сайта
        var address = "https://en.wikipedia.org/wiki/List_of_The_Big_Bang_Theory_episodes";
        // загружаем страницу и разбираем её
     
        //Метод расширения
        //Task<IDocument> OpenAsync(this IBrowsingContext context, string address);
        var document = BrowsingContext.New(config).OpenAsync(address).Result;
        // Используем CSS селектор для получения строк таблицы с классом  
        var rowSelector = "tr.vevent";
        var Строки = document.QuerySelectorAll<IHtmlTableRowElement>(rowSelector);
        foreach (var str in Строки)
    

    На TypeScript это выглядит так:

                let Net = NetObject.NetWrapper;
                let $$ = NetObject.FlagDeleteObject; // Символ для признака удаления при вызове объекта как метода
    
                // Загрузим сборку AngleSharpж
                let СборкаAngleSharp = Net.Сборка("AngleSharp");
                // Получим из неё используемые типы
                let Configuration = СборкаAngleSharp.GetType("AngleSharp.Configuration");
                let BrowsingContext = СборкаAngleSharp.GetType("AngleSharp.BrowsingContext");
                let HtmlParser = СборкаAngleSharp.GetType("AngleSharp.Parser.Html.HtmlParser");
                let IHtmlTableRowElement = СборкаAngleSharp.GetType("AngleSharp.Dom.Html.IHtmlTableRowElement");
                let ApiExtensions = СборкаAngleSharp.GetType("AngleSharp.Extensions.ApiExtensions");
    
                let Default = Configuration._Default;
                var config = Default.WithDefaultLoader();
                // Устанавливаем адрес страницы сайта
                var address = "https://en.wikipedia.org/wiki/List_of_The_Big_Bang_Theory_episodes";
                // загружаем страницу и разбираем её
    
                let Context = BrowsingContext.New(config);
    
                //Метод расширения
                //Task<IDocument> OpenAsync(this IBrowsingContext context, string address);
                let document = await Context.async.OpenAsync(address);
                // Не могу установить результат асинхронной функции класс Proxy с Target fuction
                // Поэтому для объектов нужно вручную обернуть
                document = NetObject.WrapResult(document, true);
    
                // Используем CSS селектор для получения строк таблицы с классом  
                let rowSelector = "tr.vevent";
    
                // Для дженериков пока не сделал поиск в расширениях поэтому вместо
                //let rows = document.QuerySelectorAll([IHtmlTableRowElement], rowSelector);
               
                // используем метод расширения явно
                //IEnumerable < TElement > QuerySelectorAll<TElement>(this IParentNode parent, string selectors) where TElement : IElement;
                 let rows = ApiExtensions.QuerySelectorAll([IHtmlTableRowElement], document, rowSelector);
             
                // можно и так вызвать, но нужно обыграть все варианты
                //let rows = document.QuerySelectorAll(rowSelector);
    
    // Пройдемся по нужным строкам распарсенной таблицы
                for (let row of rows) {
                    let Cells = row._Cells;
                    let i = 0;
                    let данныеСайта = new ДанныеСайта();
                    this.ResultParse.push(данныеСайта);
    // Загрузим данные ячеек в поля объекта ДанныеСайта
                    for (let Cell of Cells) {
     // Нужно дождаться окончания итератора, что бы освободить ссылку на итератор
                        if (i < 8)                        {
                        данныеСайта[this.Colums[i]] = Cell._TextContent;
                        Cell($$); // Удалим ссылку из хранилища объектов 
                        i++;
                        }
                    }
                    Cells($$);
                    row($$);
                }
                rows($$);
    
                // Удалим вручную испльзуемые объекты
                NetObject.DeleteNetObjets(СборкаAngleSharp, Configuration, BrowsingContext, HtmlParser, IHtmlTableRowElement, ApiExtensions, Default, config, Context, document); 
                alert("Количество элементов в хранилище "+Net.КоличествоЭлементовВХранилище());

    Прежде всего видим главные отличия от C#. Для получения свойства нужно добавить "_"

    let Default = Configuration._Default;

    Для вызова асинхронного метода нужно добавить ключевое слово async:

    let document = await Context.async.OpenAsync(address);

    Для вызова дженерик метода, если нельзя вывести типы по параметрам то аргументы указываем в массиве:

    let rows = ApiExtensions.QuerySelectorAll([IHtmlTableRowElement], document, rowSelector);

    Ну и главное, нужно вручную удалить ссылку на объект со стороны .Net

    Cells(NetObject.FlagDeleteObject);
    для уменьшения писанины
    Cells($$);

    По скорости вызовов на моем Intel Core i3-2120 CPU 3.3 GHz.

    Скорость вызова без Proxy 60к вызовов в секунду
    Скорость вызова с прокси Proxy 45k вызовов в секунду
    Скорость вызова итератора 160k вызовов в секунду

    Что в общем-то вполне приемлемо.

    Приведу еще небольшой пример.

     public class Тестовый
        {
           public string СвойствоОбъекта { get; set; }
           public  Тестовый(string СвойствоОбъекта)
                {
                this.СвойствоОбъекта = СвойствоОбъекта;
                }
     public object ПолучитьExpandoObject()
            {
    
                dynamic res = new ExpandoObject();
                res.Имя = "Тест ExpandoObject";
                res.Число = 456;
                res.ВСтроку = (Func<string>)(() => res.Имя);
                res.Сумма = (Func<int, int, int>)((x, y) => x + y);
    
                return res;
            }
         }

    На TypeScript можно вызвать так:

    // Получим Тип из сборки лежащей в каталоге приложения
    let Тестовый = Net.GetType("TestDllForCoreClr.Тестовый", "TestDllForCoreClr");
    // Создадим объект используя new
    let TO = new Тестовый("Свойство из Конструктора");
    // Получим ExpandoObject
    var EO = TO.ПолучитьExpandoObject();
    let Имя=EO._Имя;// Свойства через _
    let Число=EO._Число;
    let делегат = EO._ВСтроку;
    let res= делегат());// Вызовем как делегат
     // Для ExpandoObject можно вызвать как метод
     res= EO.ВСтроку());// Для ExpandoObject
    

    Теперь за счет чего это достигается. Кроссплатформенное использование классов .Net из неуправляемого кода. Или аналог IDispatch на Linux. Через CEF встраиваем нужные методы:

       declare var window: WindowInterface;
        export interface WindowInterface {
        CallNetMethod(Id: number, MethodName: string, args?: any[]): any;// Вызов метода
        CallNetDelegate(Id: number, args?: any[]): any; // Вызов делегата
        CallNetPropertySet(Id: number, PropertyName: string, value: any): void; // Установка свойства
        CallNetPropertyGet(Id: number, PropertyName: string): any; // Получение значения свойства
        DeleteNetObject(Id: number): void; // Освободить ссылку на объект со стороны .Net
        // Асинхронный вызов метода возвращающий Task или Task<T>
        CallAsyncNetObjectFunction(Id: number, MethodName: string, TaskId: string, args?: any[]): any; 
        // Регистрация метода на стороне CEF, для установки результата Promise 
        RegisterCallBacks(SetAsyncResult: (Successfully: boolean, TaskId: string, result: any) => void): void; 
        // Вызов дженерик метода с указанием типов аргументов
        CallNetObjectGenericFunction(Id: number, MethodName: string, types: any[], args?: any[]): any;
        // Вызов итератора IEnumerator MoveNext на стороне .Net
        IteratorNext(Id: number): any;
    }

    Для удобного использования этих методов создадим класс прокси с Target гибридного типа:

    export interface NetObjectinterface {
        (): void;
        Id: number;
        isNetObject: boolean;
        IsAsyncCall?: boolean;
        CallAsProp(target: NetObject, name: any): ResultCallAsProp;
        Execute: (target: NetObject, name: any, args: any[]) => any;
    
    }

    Target должен быть функцией для возможности использования new и (). Теперь нам понадобится Handler:

    export var NetObjectHandler: ProxyHandler<NetObjectinterface> = {
        get: (target, name: any) => {
    // Вызывается как PropertyGet как для свойств так и методов
    // Что бы их разделить  свойства начинаются с "_"
    
            let res = target.CallAsProp(target, name);
            if (res.Successfully)
                return res.result;
    
            return (...args: any[]) => {
                return target.Execute(target, name, args);
            }
    
        },
        set: function (target, prop, value, receiver) {
            return NetObject.SetPropertyValue(target, prop, value, receiver);
        },
    
        apply: (target, that, args) => {
            if (args.length == 1) {
                var param = args[0];
                if (param === NetObject.FlagGetObject)
                    return target;
                else if (param === NetObject.FlagDeleteObject) {
                    window.DeleteNetObject(target.Id);
                    return undefined;
                }
            }
    
            NetObject.SetArgs(args);
            let res = window.CallNetDelegate(target.Id, args)
            return NetObject.WrapResult(res, true);
        },
    
        construct: (target, argumentsList, newTarget) => {
    // Используем метод на стороне Net 
    // object Новый(object Тип, params object[] argOrig)
            NetObject.SetArgs(argumentsList);
            argumentsList.unshift(target);
            let res = window.CallNetMethod(0, "Новый", argumentsList);
            return NetObject.WrapResult(res, true);
    
        }
    }

    Ну и понадобится сам Target:

    function getNetObject(id: number): NetObjectinterface {
        let netObject = <NetObjectinterface>function (start: number) { };
        netObject.Id = id;
        netObject.isNetObject = true;
        netObject[NetObject.isNetclass] = true;
        netObject.Execute = NetObject.Execute;
        netObject.CallAsProp = NetObject.CallAsProp;
        return netObject;
    }

    Для обертки результата из CEF используется:

    static WrapResult(value: any, ReturnProxy: boolean = false): any {
            if (typeof value == "object") {
                if ("IsNetObject" in value) {
                    let res = getNetObject(value.Id);
                    if (ReturnProxy)
                        return new Proxy(res, NetObjectHandler);
                    else
                        return res
    
                }
    
    
            }
            return value;
        }

    Что касается асинхронных методов то они работают через два метода:

    static GetPromise(Target: NetObjectinterface, name: any, args: any[]) {
    
            let key = window.CallNetMethod(0, "GetUniqueString");
            let promise = new Promise((resolve, reject) => {
                NetObject.PromiseDictioanary.set(key, { resolve: resolve, reject: reject });
                window.CallAsyncNetObjectFunction(Target.Id, name, key, args);
            });
            return promise;
        }

    И при получении асинхронного результата:

     static SetPromiseResult(Successfully: boolean, TaskId: string, result: any) {
            let item = NetObject.PromiseDictioanary.get(TaskId);
            try {
    
                NetObject.PromiseDictioanary.delete(TaskId);
               // Вот здесь не могу установить результат Proxy с Target function
                //  result = NetObject.WrapResult(result, true);
               // возникает исключение "Не найден then"
                if (Successfully)
                    item.resolve(result);
                else
                    item.reject(result);
            }
    
            catch (e) {
                item.reject("ошибка установки асинхронного результата " + e);
                alert("ошибка установки асинхронного результата " + e);
            }
        }

    где:

     static PromiseDictioanary = new Map();

    Весь код можно посмотреть ниже под спойлером:

    Весь код NetProxy
    declare var window: WindowInterface;
    declare var $_: Symbol;
    declare var _$: Symbol;
    
    export interface WindowInterface {
        CallNetMethod(Id: number, MethodName: string, args?: any[]): any;// Вызов метода
        CallNetDelegate(Id: number, args?: any[]): any; // Вызов делегата
        CallNetPropertySet(Id: number, PropertyName: string, value: any): void; // Установка свойства
        CallNetPropertyGet(Id: number, PropertyName: string): any; // Полусение значения свойства
        DeleteNetObject(Id: number): void; // Освободить ссылку на объект со стороны .Net
        // Асинхронный вызов метода возвращающий Task или Task<T>
        CallAsyncNetObjectFunction(Id: number, MethodName: string, TaskId: string, args?: any[]): any; 
        // Регистрация метода на стороне CEF, для установки результата Promise 
        RegisterCallBacks(SetAsyncResult: (Successfully: boolean, TaskId: string, result: any) => void): void; 
        // Вызов дженерик метода с указанием типов аргументов
        CallNetObjectGenericFunction(Id: number, MethodName: string, types: any[], args?: any[]): any;
        // Вызов итератора IEnumerator MoveNext на стороне .Net
        IteratorNext(Id: number): any;
    }
    
    class ResultCallAsProp {
        constructor(public Successfully: boolean, public result?: any) { };
    }
    export interface NetObjectinterface {
        (): void;
        Id: number;
        isNetObject: boolean;
        IsAsyncCall?: boolean;
        CallAsProp(target: NetObject, name: any): ResultCallAsProp;
        Execute: (target: NetObject, name: any, args: any[]) => any;
    
    }
    
    export var NetObjectHandler: ProxyHandler<NetObjectinterface> = {
        get: (target, name: any) => {
    
    
            let res = target.CallAsProp(target, name);
            if (res.Successfully)
                return res.result;
    
            return (...args: any[]) => {
                return target.Execute(target, name, args);
            }
    
    
        },
        set: function (target, prop, value, receiver) {
            return NetObject.SetPropertyValue(target, prop, value, receiver);
        },
    
        apply: (target, that, args) => {
            if (args.length == 1) {
                var param = args[0];
                if (param === NetObject.FlagGetObject)
                    return target;
                else if (param === NetObject.FlagDeleteObject) {
                    window.DeleteNetObject(target.Id);
                    return undefined;
                }
            }
    
            NetObject.SetArgs(args);
            let res = window.CallNetDelegate(target.Id, args)
            return NetObject.WrapResult(res, true);
        },
    
        construct: (target, argumentsList, newTarget) => {
    
            //  var res = NetObject.GetNetObject(5);
            //  return new Proxy(res, NetObjectHandler)
            NetObject.SetArgs(argumentsList);
            argumentsList.unshift(target);
            let res = window.CallNetMethod(0, "Новый", argumentsList);
            return NetObject.WrapResult(res, true);
    
        }
    
    
    }
    
    function getNetObject(id: number): NetObjectinterface {
        let netObject = <NetObjectinterface>function (start: number) { };
        netObject.Id = id;
        netObject.isNetObject = true;
        netObject[NetObject.isNetclass] = true;
        netObject.Execute = NetObject.Execute;
        netObject.CallAsProp = NetObject.CallAsProp;
        return netObject;
    }
    
    function GetNetProxy(): any {
        let res = getNetObject(0);
        if (NetObject.FlagFirstLoad) {
            try {
                window.RegisterCallBacks(NetObject.SetPromiseResult);
    
            }
            catch (e) {
                // alert("ошибка " + e);
            }
    
            NetObject.FlagFirstLoad = false;
        }
    
        return new Proxy(res, NetObjectHandler);
    
    }
    export class NetObject {
        static GetNetObject(id: number) { return getNetObject(id); }
        static isNetclass = Symbol();
        static IsAsyncCall = Symbol();
        static FlagGetObject = Symbol();
        static FlagDeleteObject = Symbol();
        static FlagFirstLoad = true;
        static NetWrapper = GetNetProxy();
    
        static PromiseDictioanary = new Map();
        static GetIterator(target: NetObjectinterface): any {
            return function () {
                let IdIterator = window.CallNetMethod(0, "GetIterator", [target]).Id;
    
                return {
                    next: function () {
    
                        let value = window.IteratorNext(IdIterator);
                        if (value === undefined) {
                            return { value: undefined, done: true };
    
                        } else
                            return { value: NetObject.WrapResult(value, true), done: false }
    
                    }
                }
    
    
            }
        }
    
    
        static WrapResult(value: any, ReturnProxy: boolean = false): any {
            if (typeof value == "object") {
                if ("IsNetObject" in value) {
                    let res = getNetObject(value.Id);
                    if (ReturnProxy)
                        return new Proxy(res, NetObjectHandler);
                    else
                        return res
    
                }
    
    
            }
            return value;
        }
    
        static WrapObject(value: any): any {
            if (typeof value == "function") {
                if (NetObject.isNetclass in value)
                    return new Proxy(value, NetObjectHandler);
            }
        }
    
        static GetPropertyValue(target: NetObjectinterface, name: any): any {
            let res = window.CallNetPropertyGet(target.Id, name);
            return NetObject.WrapResult(res, true);
    
        }
    
        static SetPropertyValue(target: NetObjectinterface, prop: any, value: any, receiver: any): any {
            let res = window.CallNetPropertySet(target.Id, prop, NetObject.GetTarget(value));
            return true;
    
        }
    
        static CallAsProp(Target: NetObjectinterface, name: any): ResultCallAsProp {
            if (name === Symbol.iterator) {
                return new ResultCallAsProp(true, NetObject.GetIterator(Target));
            }
    
            if (name === Symbol.toPrimitive) {
                return new ResultCallAsProp(true, () => { return `Id= ${Target.Id}, isNetObject= ${Target.isNetObject}` });
            }
            if (name.startsWith('_')) {
    
                return new ResultCallAsProp(true, NetObject.GetPropertyValue(Target, name.substring(1)));
    
            }
    
            if (name === "async") {
    
                let res = getNetObject(Target.Id);
    
                res.Execute = NetObject.ExecuteAsync;
                res.CallAsProp = NetObject.CallAsPropAsync;
                return new ResultCallAsProp(true, new Proxy(res, NetObjectHandler));
            }
    
            return new ResultCallAsProp(false);
        }
    
        static CallAsPropAsync(Target: NetObjectinterface, name: any): ResultCallAsProp {
    
    
            return new ResultCallAsProp(false);
        }
    
        static GetPromise(Target: NetObjectinterface, name: any, args: any[]) {
    
            let key = window.CallNetMethod(0, "GetUniqueString");
            let promise = new Promise((resolve, reject) => {
                NetObject.PromiseDictioanary.set(key, { resolve: resolve, reject: reject });
                window.CallAsyncNetObjectFunction(Target.Id, name, key, args);
            });
            return promise;
        }
    
        static GetTarget(obj: any): any {
            if (typeof obj == "function") {
                if (NetObject.isNetclass in obj)
                    return obj(NetObject.FlagGetObject);
    
    
            }
            return obj;
        }
    
        static SetArgs(args: any[]) {
            for (let i in args) {
                let obj = args[i];
                if (typeof obj == "function") {
                    if (NetObject.isNetclass in obj)
                        args[i] = obj(NetObject.FlagGetObject);
    
    
                }
    
            }
        }
    
    
        static SetPromiseResult(Successfully: boolean, TaskId: string, result: any) {
            let item = NetObject.PromiseDictioanary.get(TaskId);
            try {
    
                NetObject.PromiseDictioanary.delete(TaskId);
                //  result = NetObject.WrapResult(result, true);
                if (Successfully)
                    item.resolve(result);
                else
                    item.reject(result);
            }
    
            catch (e) {
                item.reject("ошибка установки асинхронного результата " + e);
                alert("ошибка установки асинхронного результата " + e);
            }
        }
    
        static CheckGenericMethod(args: any[]): any {
    
            var argsCount = args.length;
    
            if (argsCount > 0 && args[0] instanceof Array) {
                var types = args[0].slice();
                NetObject.SetArgs(types);
    
                var args2 = args.slice(1);
                NetObject.SetArgs(args2);
                return { IsGeneric: true, types: types, args: args2 }
            }
    
            return { IsGeneric: false };
    
        }
        static Execute(Target: NetObjectinterface, name: any, args: any[]) {
    
            let res = undefined;
            let chek = NetObject.CheckGenericMethod(args);
    
            if (chek.IsGeneric) {
                res = window.CallNetObjectGenericFunction(Target.Id, name, chek.types, chek.args);
    
            }
            else {
                NetObject.SetArgs(args);
    
                res = window.CallNetMethod(Target.Id, name, args);
            }
    
            return NetObject.WrapResult(res, true);
        }
    
        static ExecuteAsync(Target: NetObjectinterface, name: any, args: any[]) {
    
    
            let res = undefined;
            let chek = NetObject.CheckGenericMethod(args);
    
            if (chek.IsGeneric) {
                let Target0 = getNetObject(0);
                let task = window.CallNetObjectGenericFunction(Target.Id, name, chek.types, chek.args);
                res = NetObject.GetPromise(Target0, "ReturnParam", [getNetObject(task.Id)]);
                window.DeleteNetObject(task.Id);
    
            }
            else {
                NetObject.SetArgs(args);
    
                res = NetObject.GetPromise(Target, name, args);
            }
    
            return res;
        }
    
        static New(Target: NetObjectinterface, name: any, args: any[]): any {
            NetObject.SetArgs(args);
            var res = window.CallNetMethod(0, "Новый", args);
            return NetObject.WrapResult(res, true);
        }
    
        static DeleteNetObjets(...args: any[]) {
    
            for (let item of args)
                item(NetObject.FlagDeleteObject);
        }
    
    
    }


    Прошу прощение за моё незнание С++. Но, делать было нужно сейчас, а я на нем не пишу.
    Не смог прикрутить Dev Tools к CefSimple:

    Код CEF обертки для обмена между JS и .Net Core
    #include "include/CEF_V8.H"
    #include "ManagedDomainLoader.h"
    #include "CefV8HandlersForNet.h"
    
    #include "types.h"
    #include "NetConverter.h"
    
    
    #include "include/base/cef_bind.h"
    #include "include/wrapper/cef_closure_task.h"
    #include <thread>
    #include "include/base/cef_platform_thread.h"
    namespace NetObjectToNative{
    
    	BaseClassForNetHandlers::BaseClassForNetHandlers(ManagedDomainLoader* mD)
    	{
    		this->mD = mD;
    	}
    
    	 bool CallNetObjectFunction::Execute(const CefString& name,
    		CefRefPtr<CefV8Value> object,
    		const CefV8ValueList& arguments,
    		CefRefPtr<CefV8Value>& retval,
    		CefString& exception)  {
    
    
    		const size_t argumentsCount = arguments.size();
    		vector<wstring> savedstrings;
    		NetObjectToNative::tVariant* Params = nullptr;
    
    		int Target = arguments[0]->GetIntValue();
    		wstring MethodMame = arguments[1]->GetStringValue().ToWString();
    
    		CefRefPtr<CefV8Value> params;
    
    		size_t  argCount = 0;
    		if (argumentsCount == 3)
    		{
    
    
    			params = arguments[2];
    
    			if (!params->IsArray())
    			{
    				exception = CefString(L"Для вызова метода 3 параметр должен быть массивом");
    				return true;
    
    			}
    			argCount = params->GetArrayLength();
    
    
    		}
    
    		if (argCount > 0)
    		{
    			savedstrings.reserve(argCount);
    			Params = new NetObjectToNative::tVariant[argumentsCount];
    			NetObjectToNative::tVariant* Param = Params;
    
    			for (size_t i = 0; i < argCount; ++i)
    			{
    
    				NetObjectToNative::ConvertCEFtoNet(params->GetValue(i), &Param[i], savedstrings);
    			}
    
    		}
    		wchar_t*  Error = nullptr;
    		NetObjectToNative::tVariant RetVal;
    
    		bool res = mD->pCallAsFunc(Target, MethodMame.c_str(), &RetVal, Params, argCount, &Error);
    
    		if (res)
    		{
    
    			retval = NetObjectToNative::ConvertNetToCef(&RetVal, true);
    		}
    		else
    		{
    			if (Error)
    				exception = CefString(std::wstring(Error));
    			delete Error;
    		}
    
    		if (Params) delete[] Params;
    
    		return true;
    	}
    
    	 //====================== ============================================
    	 bool CallAsyncNetObjectFunction::Execute(const CefString& name,
    		 CefRefPtr<CefV8Value> object,
    		 const CefV8ValueList& arguments,
    		 CefRefPtr<CefV8Value>& retval,
    		 CefString& exception) {
    
    
    		 const size_t argumentsCount = arguments.size();
    		 vector<wstring> savedstrings;
    		 NetObjectToNative::tVariant* Params = nullptr;
    
    		 int Target = arguments[0]->GetIntValue();
    		 wstring MethodMame = arguments[1]->GetStringValue().ToWString();
    		 wstring TaskId = arguments[2]->GetStringValue().ToWString();
    
    		 CefRefPtr<CefV8Value> params;
    
    		 size_t  argCount = 0;
    		 if (argumentsCount == 4)
    		 {
    
    
    			 params = arguments[3];
    
    			 if (!params->IsArray())
    			 {
    				 exception = CefString(L"Для вызова асинхронного метода 4 параметр должен быть массивом");
    				 return true;
    
    			 }
    			 argCount = params->GetArrayLength();
    
    
    		 }
    
    		 if (argCount > 0)
    		 {
    			 savedstrings.reserve(argCount);
    			 Params = new NetObjectToNative::tVariant[argumentsCount];
    			 NetObjectToNative::tVariant* Param = Params;
    
    			 for (size_t i = 0; i < argCount; ++i)
    			 {
    
    				 NetObjectToNative::ConvertCEFtoNet(params->GetValue(i), &Param[i], savedstrings);
    			 }
    
    		 }
    		 wchar_t*  Error = nullptr;
    		 NetObjectToNative::tVariant RetVal;
    
    		 //bool res = mD->pCallAsFunc(Target, MethodMame.c_str(), &RetVal, Params, argCount, &Error);
    		 bool res = mD->pCallAsyncFunc(Target, MethodMame.c_str(), this->cfn, TaskId.c_str(), Params, argCount, &Error);
    
    		 if (res)
    		 {
    
    			 retval = NetObjectToNative::ConvertNetToCef(&RetVal, true);
    		 }
    		 else
    		 {
    			 if (Error)
    				 exception = CefString(std::wstring(Error));
    			 delete Error;
    		 }
    
    		 if (Params) delete[] Params;
    
    		 return true;
    	 }
    
    	//============================ Call Generic Function
    
    	 bool CallNetObjectGenericFunction::Execute(const CefString& name,
    		 CefRefPtr<CefV8Value> object,
    		 const CefV8ValueList& arguments,
    		 CefRefPtr<CefV8Value>& retval,
    		 CefString& exception) {
    
    
    		 const size_t argumentsCount = arguments.size();
    		 vector<wstring> savedstrings;
    		 NetObjectToNative::tVariant* Params = nullptr;
    		 NetObjectToNative::tVariant* ParamsTypes = nullptr;
    
    		 int Target = arguments[0]->GetIntValue();
    		 wstring MethodMame = arguments[1]->GetStringValue().ToWString();
    
    		 CefRefPtr<CefV8Value> params;
    		 CefRefPtr<CefV8Value> types= arguments[2];
    		 size_t  typesCount= types->GetArrayLength();
    
    
    		 size_t  argCount = 0;
    		 if (argumentsCount == 4)
    		 {
    
    
    			 params = arguments[3];
    
    			 if (!params->IsArray())
    			 {
    				 exception = CefString(L"Для вызова метода 4 параметр должен быть массивом");
    				 return true;
    
    			 }
    			 argCount = params->GetArrayLength();
    
    
    		 }
    
    		 
    		 savedstrings.reserve(argCount+ typesCount);
    		 ParamsTypes = new NetObjectToNative::tVariant[typesCount];
    		 for (size_t i = 0; i < typesCount; ++i)
    		 {
    
    			 NetObjectToNative::ConvertCEFtoNet(types->GetValue(i), &ParamsTypes[i], savedstrings);
    		 }
    
    
    		 if (argCount > 0)
    		 {
    			
    			 Params = new NetObjectToNative::tVariant[argumentsCount];
    			 NetObjectToNative::tVariant* Param = Params;
    
    			 for (size_t i = 0; i < argCount; ++i)
    			 {
    
    				 NetObjectToNative::ConvertCEFtoNet(params->GetValue(i), &Param[i], savedstrings);
    			 }
    
    		 }
    
    
    
    		 wchar_t*  Error = nullptr;
    		 NetObjectToNative::tVariant RetVal;
    
    		 bool res = mD->pCallAsGenericFunc(Target, MethodMame.c_str(), &RetVal, ParamsTypes, typesCount, Params, argCount, &Error);
    
    		 if (res)
    		 {
    
    			 retval = NetObjectToNative::ConvertNetToCef(&RetVal, true);
    		 }
    		 else
    		 {
    			 if (Error)
    				 exception = CefString(std::wstring(Error));
    			 delete Error;
    		 }
    
    		 if (Params) delete[] Params;
    		 delete[] ParamsTypes;
    
    		 return true;
    	 }
    
    
    	 //===================== CallNetDelegate
    
    	 bool CallNetDelegate::Execute(const CefString& name,
    		 CefRefPtr<CefV8Value> object,
    		 const CefV8ValueList& arguments,
    		 CefRefPtr<CefV8Value>& retval,
    		 CefString& exception) {
    
    
    		 const size_t argumentsCount = arguments.size();
    		 vector<wstring> savedstrings;
    		 NetObjectToNative::tVariant* Params = nullptr;
    
    		 int Target = arguments[0]->GetIntValue();
    		
    
    		 CefRefPtr<CefV8Value> params;
    
    		 size_t  argCount = 0;
    		 if (argumentsCount == 2)
    		 {
    
    
    			 params = arguments[1];
    
    			 if (!params->IsArray())
    			 {
    				 exception = CefString("Для вызова делегата  2 параметр должен быть массивом");
    				 return true;
    
    			 }
    			 argCount = params->GetArrayLength();
    
    
    		 }
    
    		 if (argCount > 0)
    		 {
    			 savedstrings.reserve(argCount);
    			 Params = new NetObjectToNative::tVariant[argumentsCount];
    			 NetObjectToNative::tVariant* Param = Params;
    
    			 for (size_t i = 0; i < argCount; ++i)
    			 {
    
    				 NetObjectToNative::ConvertCEFtoNet(params->GetValue(i), &Param[i], savedstrings);
    			 }
    
    		 }
    		 wchar_t*  Error = nullptr;
    		 NetObjectToNative::tVariant RetVal;
    
    		 bool res = mD->pCallAsDelegate(Target, &RetVal, Params, argCount, &Error);
    
    		 if (res)
    		 {
    
    			 retval = NetObjectToNative::ConvertNetToCef(&RetVal, true);
    		 }
    		 else
    		 {
    			 if (Error)
    				 exception = CefString(std::wstring(Error));
    			 delete Error;
    		 }
    
    		 if (Params) delete[] Params;
    
    		 return true;
    	 }
    
    	 // CallNetObjectPropertySet
    	 bool 	CallNetObjectPropertySet::Execute(const CefString& name,
    		 CefRefPtr<CefV8Value> object,
    		 const CefV8ValueList& arguments,
    		 CefRefPtr<CefV8Value>& retval,
    		 CefString& exception) {
    
    
    		 const size_t argumentsCount = arguments.size();
    
    		 if (argumentsCount != 3)
    		 {
    
    
    				 exception = CefString(L"Для PropertySet должно быть 3 параметра");
    				 return true;
    
    			}
    			 
    		 vector<wstring> savedstrings;
    
    
    		 int Target = arguments[0]->GetIntValue();
    		 wstring PropertyName = arguments[1]->GetStringValue().ToWString();
    		 CefRefPtr<CefV8Value> value = arguments[2];
    
    			 
    			 savedstrings.reserve(1);
    			 NetObjectToNative::tVariant Param;
    			
    			 NetObjectToNative::ConvertCEFtoNet(value, &Param, savedstrings);
    			 
    
    
    		 wchar_t*  Error = nullptr;
    	
    		 bool res = mD->pSetPropVal(Target, PropertyName.c_str(), &Param, &Error);
    
    		 if (!res)
    		 {
    			 if (Error)
    			 {
    				 exception = CefString(std::wstring(Error));
    				 delete Error;
    			 }
    			 else 
    				 exception = CefString(L"Ошибка при установке свойства"+ PropertyName);
    			
    		 }
    
    		
    
    		 return true;
    	 }
    
    	 bool 	DeleteNetObject::Execute(const CefString& name,
    		 CefRefPtr<CefV8Value> object,
    		 const CefV8ValueList& arguments,
    		 CefRefPtr<CefV8Value>& retval,
    		 CefString& exception) {
    
    
    		 const size_t argumentsCount = arguments.size();
    
    		 if (argumentsCount != 1)
    		 {
    			 exception = CefString(L"Для DeleteObject Должно быть 1 параметра");
    			 return true;
    		 }
    
    		 CefRefPtr<CefV8Value> value = arguments[0];
    		 
    		 
    		 mD->pDeleteObject(value->GetIntValue());
    
    		
    
    		 return true;
    	 }
    
    	 bool 	IteratorNext::Execute(const CefString& name,
    		 CefRefPtr<CefV8Value> object,
    		 const CefV8ValueList& arguments,
    		 CefRefPtr<CefV8Value>& retval,
    		 CefString& exception) {
    
    
    		 const size_t argumentsCount = arguments.size();
    
    		 if (argumentsCount != 1)
    		 {
    			 exception = CefString(L"Для IteratorNext Должно быть 1 параметра");
    			 return true;
    		 }
    
    		 CefRefPtr<CefV8Value> value = arguments[0];
    		 wchar_t*  Error = nullptr;
    		 NetObjectToNative::tVariant RetVal;
    
    		bool res= mD->pIteratorNext(value->GetIntValue(),&RetVal, &Error);
    		if (res)
    		{
    			retval = NetObjectToNative::ConvertNetToCef(&RetVal, true);
    
    		}
    		else
    		{
    			retval = CefV8Value::CreateUndefined();
    			if (Error)
    			{
    				exception = CefString(std::wstring(Error));
    				delete Error;
    			}
    
    		}
    		 return true;
    	 }
    
    	 bool 	CallNetObjectPropertyGet::Execute(const CefString& name,
    		 CefRefPtr<CefV8Value> object,
    		 const CefV8ValueList& arguments,
    		 CefRefPtr<CefV8Value>& retval,
    		 CefString& exception) {
    
    
    		 int Target = arguments[0]->GetIntValue();
    		 wstring PropertyName = arguments[1]->GetStringValue().ToWString();
    
    		 wchar_t*  Error = nullptr;
    		 NetObjectToNative::tVariant RetVal;
    
    		 bool res = mD->pGetPropVal(Target, PropertyName.c_str(), &RetVal,&Error);
    
    		 if (!res)
    		 {
    			 if (Error)
    			 {
    				 exception = CefString(std::wstring(Error));
    				 delete Error;
    			 }
    			 else
    				 exception = CefString(L"Ошибка при установке свойства " + PropertyName);
    
    		 }
    		 else
    			 retval = NetObjectToNative::ConvertNetToCef(&RetVal, true);
    
    
    
    		 return true;
    	 }
    
    	 void SetHandlerToContex(CefRefPtr<CefV8Handler> Handler, CefRefPtr<CefV8Value> object, const char* MetodName)
    	 {
    
    		 CefRefPtr<CefV8Value> CallNetObject = CefV8Value::CreateFunction(MetodName, Handler);
    
    		 // Add the "myfunc" function to the "window" object.
    		 object->SetValue(MetodName, CallNetObject, V8_PROPERTY_ATTRIBUTE_NONE);
    	 }
    
    	 void ContextForNetHandlers::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
    	 {
    		 this->context = context;
    		 // Retrieve the context's window object.
    		 CefRefPtr<CefV8Value> object = context->GetGlobal();
    		 NetObjectToNative::ManagedDomainLoader* mD = NetObjectToNative::ManagedDomainLoader::InitManagedDomain(L"c:\\Program Files\\DNX\\runtimes\\dnx-coreclr-win-x86.1.0.0-rc1-update1\\bin\\", L"", L"");
    
    		 //=========== CallNetMethod =======================================================
    		 SetHandlerToContex(new CallNetObjectFunction(mD), object, "CallNetMethod");
    		 //=========== CallNetDelegate =======================================================
    		 SetHandlerToContex(new CallNetDelegate(mD), object, "CallNetDelegate");
    		 //=========== PropertySet =======================================================
    		 SetHandlerToContex(new CallNetObjectPropertySet(mD), object, "CallNetPropertySet");
    		 //=========== PropertyGet =======================================================
    		 SetHandlerToContex(new CallNetObjectPropertyGet(mD), object, "CallNetPropertyGet");
    		 //=========== PropertyGet =======================================================
    		 SetHandlerToContex(new DeleteNetObject(mD), object, "DeleteNetObject");
    		 //=========== SetCallBacks =======================================================
    		 SetHandlerToContex(new SetCallBacks(mD, this, object), object, "RegisterCallBacks");
    		 //============ CallAsyncNetObjectFunction ================================
    		 SetHandlerToContex(new CallAsyncNetObjectFunction(mD, this), object, "CallAsyncNetObjectFunction");
    		 //============ CallNetObjectGenericFunction ================================
    		 SetHandlerToContex(new CallNetObjectGenericFunction(mD), object, "CallNetObjectGenericFunction");
    		 //============ IteratorNext ================================
    		 SetHandlerToContex(new IteratorNext(mD), object, "IteratorNext");
    
    	 }
    
    	
    
    	 
    	 void ContextForNetHandlers::AsyncCalBack(const wchar_t* TaskID, bool Successfully, tVariant* ReturnValue)
    	 {
    		
    
    		 if (!CefCurrentlyOn(TID_RENDERER)) {
    			 // Execute on the UI thread.
    			// CefPostTask(TID_UI, base::Bind(&AsyncCalBack2, TaskID, Successfully,ReturnValue, CallbackContext));
    			 CefPostTask(TID_RENDERER, base::Bind(&SetCallBacks::AsyncCalBack, this->scb, TaskID, Successfully, ReturnValue));
    			 return;
    		 }
    
    		 scb->AsyncCalBack(TaskID, Successfully, ReturnValue);
    	 }
    
    	 //==================== Set CallBacs
    	 bool SetCallBacks::Execute(const CefString& name,
    		 CefRefPtr<CefV8Value> object,
    		 const CefV8ValueList& arguments,
    		 CefRefPtr<CefV8Value>& retval,
    		 CefString& exception) {
    
    		    this_id = std::this_thread::get_id();
    			 if (arguments.size() == 1 && arguments[0]->IsFunction()) {
    				 AsyncMetodCall = arguments[0];
    				 CallbackContext = CefV8Context::GetCurrentContext();
    				 cfn->scb = this;
    
    				 /*CefV8ValueList args;
    				 args.push_back(CefV8Value::CreateBool(true));
    				 args.push_back(CefV8Value::CreateString(L"Первый"));
    				 args.push_back(CefV8Value::CreateString(L"Второй"));
    
    				 if (AsyncMetodCall->ExecuteFunctionWithContext(CallbackContext, globalObj, args)) {
    					
    				 }*/
    				
    				 return true;
    			 }
    		
    
    		 return true;
    
    	 }
    
    	 void SetCallBacks::AsyncCalBack(const wchar_t* TaskID, bool Successfully, tVariant* ReturnValue)
    	 {
    		 CefV8ValueList args;
    		 
    		 std::thread::id Curr_id = std::this_thread::get_id();
    		 if (this_id != Curr_id)
    		 {
    		 }
    
    		 if (CallbackContext.get() && CallbackContext->Enter()) {
    
    			 args.push_back(CefV8Value::CreateBool(true));
    
    			 args.push_back(CefV8Value::CreateString(TaskID));
    			 delete[] TaskID;
    
    			 if (ReturnValue==nullptr)
    				 args.push_back(CefV8Value::CreateUndefined());
    			 else
    			 {
    			 args.push_back(NetObjectToNative::ConvertNetToCef(ReturnValue, true));
    			 delete[] ReturnValue;
    			 }
     
    			 
    			 if (AsyncMetodCall->ExecuteFunctionWithContext(CallbackContext, globalObj, args)) {
    				 
    			 }
    			 CallbackContext->Exit();
    		 }
    	 }	
    }
    


    В планах добавить события по аналогии с 1С,.Net Core. Динамическая компиляция класса обертки для получения событий .Net объекта в 1С.

    Если вдруг кого то заинтересовало, то проекты и исходники можно скачать здесь.

    Краткое описание содержимого. В каталоге cefsimple\Release\ лежит исполняемый файл с библиотеками и начальной страницей Test.html. В каталоге cefsimple\NetObjectToNative\
    лежат все файлы для обмена между CEF и .Net Core. ManagedDomainLoader и ClrLoader отвечают за загрузку .Net Core, получения и передачу методов для обмена данными.

    В CefV8HandlersForNet реализованы Хэндлеры для обмена между JS и CEF. В NetConverter конвертация данными между Net и Cef.

    В NetObjectToCEF лежат файлы которые реализуют обмен с CEF. В TestDllForCoreClr лежат все используемые примеры для Тестовый.

    В файле TestTypeScript\TestTypeScript\app\ лежат файлы ts которые и реализуют Proxy. NetProxy.ts файл реализующий Proxy.

    home.component.ts тест с AngleSharp. counter.component.ts различные тесты возможностей. TestSpeed.ts тесты скорости выполнения

    Так жепроект без node_modules. установите через вызов в директории TestTypeScript npm install

    Суть тестов такова. Запускаете TestTypeScript и CefProgects\cefsimple\Release\cefsimple.exe. На начальной странице можно попробовать тесты на JS. Для использования тестов на TS нужно перейти на сайт который нужно указать в поле ниже «Введите адрес сайта « что бы перейти на него»». Там три теста.

    Если хотите компилировать cefsimple. То скачайте отсюда opensource.spotify.com/cefbuilds/index.html 32-разрядный Standard Distribution и замените в директории tests\cefsimple\ сс и h файлы и скопируйте директорию NetObjectToNative.

    Для использования VS 2015 введите в корневом каталоге CEF cmake.exe -G «Visual Studio 14»

    Для VS 2017 cmake.exe -G «Visual Studio 15 2017».

    Спасибо за внимание!
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 255
    • +1
      Смысл показывать здесь код, который никому не пригодится?
      Вы, конечно, молодец, но это здесь совершенно не нужно, причем даже вредно — новички могут ужаснуться.
      • –1
        На самом деле здесь много интересного. Это и Proxy и Promise для TypeScript.
        Работа с CEF, а так же и Net Core. Кроме того здесь показано как просто можно использовать классы .Net очень близко к кодированию на C#. Здесь очень много информации на любой вкус.
        • +2
          Я, как человек, который первый раз видит этот код могу четко сказать, что он никого ничему не научит.
          Учатся на простых и ясных примерах, а не на коде, который интересен только его разработчику.
        • 0
          Ну у меня и не было цели учить новичков. Главная моя цель показать как можно легко использовать классы .Net в TypeScript и каким образом это достигается. Для меня такие статьи очень познавательны. Здесь собрано много вещей, аналогов которых нет, или их просто сложно найти. На многие вопросы ни на одном форуме не было ни одного ответа. Ну и опять же чем сложен этот пример?
          Сразу прошу прощения за руслиш.

          // Получим Тип из сборки лежащей в каталоге приложения
          let Тестовый = Net.GetType("TestDllForCoreClr.Тестовый", "TestDllForCoreClr");
          // Создадим объект используя new
          let TO = new Тестовый("Свойство из Конструктора");
          // Получим ExpandoObject
          var EO = TO.ПолучитьExpandoObject();
          let Имя=EO._Имя;// Свойства через _
          let Число=EO._Число;
          let делегат = EO._ВСтроку;
          let res= делегат());// Вызовем как делегат
           // Для ExpandoObject можно вызвать как метод
           res= EO.ВСтроку());// Для ExpandoObject
          
          


          Показано как просто можно использовать классы .Net Core
          • 0
            Главная моя цель показать как можно легко использовать классы .Net в TypeScript и каким образом это достигается

            Но зачем, зачем это делать? Если у меня есть доступ к .net, то я уже и без TS обойдусь.

            • 0
              На самом деле я не видел где есть полный доступ к классам .Net из браузера. Если подскажешь то буду благодарен. Сейчас например для Linux нет аналога WPF, а моя разработка помогает использовать кроссплатформенный .Net Core в браузере, или просто расширить возможности браузера за счет классов .Net
              • –1
                На самом деле я не видел где есть полный доступ к классам .Net из браузера. Если подскажешь то буду благодарен.

                Не подскажу, потому что этого нет. А нет этого, потому что это небезопасно.


                Сейчас например для Linux нет аналога WPF, а моя разработка помогает использовать кроссплатформенный .Net Core в браузере

                Угу. В каком? У меня шесть, что ли, устройств на трех операционных системах, 5 браузеров — на скольких из них это будет работать?

                • –1
                  Ну в статье же написано про CEF

                  Внизу статьи показаны ссылки на программы которые можно запустить. В начале статьи
                  Можно сделать определенную конфигурацию CEF для всех платформ и можно делать кросспалатформенные декстопные приложения.


                  Ребята читайте пожалуйста внимательнее, или подскажите как лучше написать.
                  • 0
                    Ну в статье же написано про CEF

                    Написано, ага. CEF работает на Windows Phone? iOS?


                    Внизу статьи показаны ссылки на программы которые можно запустить.

                    Агу. С сайтом (который у меня не собирается). Спасибо, но нет.

                    • –1
                      Для WinFone и прочего есть xamarin. А вот для Linux ничего нет.
                      Сайт это TypeScript? то там нужно npm install сделать, что бы установить создать папку node_modules

                      • 0
                        Для WinFone и прочего есть xamarin.

                        Да там много что есть, только получается, что решение как-то не очень кросс-платформенное.


                        Сайт это TypeScript? то там нужно npm install сделать, что бы установить создать папку node_modules

                        … и npm у меня тоже нет. Про что и речь.

                        • 0
                          Ну речь то про Angular. Я просто еще тот вэб программист. Просто JS созданные на TS напрямую не идут. Речь про await. Но внутри есть Test.html его можно посмотреть и там есть различные тесты. Правда без Proxy
                          • 0

                            Вот я про это с самого начала и говорю: много прыжков и ужимок, чтобы получить функциональность, польза которой совершенно не очевидна.

                            • –1
                              Я сейчас разберусь как можно локально использовать TypeScript и ужимок не будет. Если хочешь помоги. Буду благодарен. Все ts файлы лежат в папке ap.
                              Еще раз я один и мне приходится изучать кучу вещей. И времени просто не хватает.
                          • 0
                            Кстати а можешь пояснить, за что минус? Проблема в том, что для Linux сейчас не UI. При этом много крика про импортозамещение.
                            • 0

                              Не ко мне вопрос, не мой минус.


                              А крики про импортозамещение как были криками, так и останутся. О каком импортозамещении вы говорите, используя .net core и CEF?

                              • 0
                                Еще раз. У тебя есть приложение на WPF, UWP. C выходом NetStandard 2 возможности .Net Core приблизятся к UWP/
                                Можно достаточно легко перевести приложение под WPF на Angular 2 и использовать под Linux
                                • +1
                                  Можно достаточно легко перевести приложение под WPF на Angular 2

                                  Серьезно?


                                  (Не говоря уже о том, что приложение для iOS вряд ли будет на WPF)


                                  Понимаете ли, в моих конкретных реалиях оказалось выгоднее под каждую мобилку писать свое собственное приложение с нативным интерфейсом, потому что бэкэнд все равно, как и полагается бэкэнду, на сервере. И все эти прыжки и ужимки с "кросплатформенным-html-js-в-кросплатформенном-браузере-который-общается-с-кроссплатформенным-.net" умерли еще на первой стадии, когда не взлетел кроссплатформенный интерфейс.


                                  При этом в соседнем окне у меня Slack, написанный как раз на чем-то типа Electron (просто не помню деталей), и он как раз хорошо справляется — но у него, опять-таки, вся логика на сервере, он просто не отличается от того, что можно запускать в браузере.

                                  • 0
                                    Ну так CEF то есть и по WPF http://opensource.spotify.com/cefbuilds/index.html

                                    Опять же я просто показываю решение. Я в самом начале написал, что это мало кому интересно. Просто делюсь опытом. Я же тебя не заставляю использовать.
                                    • 0
                                      Ну так CEF то есть и по WPF http://opensource.spotify.com/cefbuilds/index.html

                                      Что такое "CEF по WFP"?


                                      Опять же я просто показываю решение. Я в самом начале написал, что это мало кому интересно. Просто делюсь опытом. Я же тебя не заставляю использовать.

                                      Вы делитесь опытом, мы делимся мнениями по поводу вашего опыта. Все логично.

                                      • 0
                                        Прошу прощения. Wpf здесь лишнее.
                                        Спасибо. Просто я сейчас не смогу отвечать. Много работы. Но все равно огромное спасибо!
                • 0
                  Я думаю можно таким образом смешать Electron+Angular2, например, как UI, и .NET как бекенда.
                  • 0

                    Если вы хотите .net на бэкенде — поставьте его там и выставьте сервис.

                    • 0
                      Городить сервис на http\ws и клиентскую часть? Появятся накладные расходы на сериализацию данных, отправку запроса, десериализацию, обработку…
                      А тут можно все в одном процессе. У такого подхода есть плюсы и минусы, но он заслуживает право существовать.
                      • +1

                        … у конверсии данных JS-.net нет накладных расходов? JS выполнется в том же домене, что и .net? Не поверю.


                        (не говоря уже о том, что бэкенд в подавляющей части случаев все равно удаленный)

                        • 0
                          В статье есть тесты на вызовы
                          Скорость вызова без Proxy 60к вызовов в секунду
                          Скорость вызова с прокси Proxy 45k вызовов в секунду
                          Скорость вызова итератора 160k вызовов в секунду

                          Можно же скачать исходники и все пощупать.
                          • 0

                            … и как это говорит об отсутствии накладных расходов?

                            • 0
                              Они минимальны по сравнению с http\ws.
                              При этом часто нужно работать с торговым оборудованием или дисками и прочим оборудованием. Сейчас кстати пишу оберки для использования событий .Net классов
                              • 0
                                Они минимальны по сравнению с http\ws.

                                Цифры в студию.

                                • 0
                                  Еще раз
                                  Скорость вызова без Proxy 60к вызовов в секунду
                                  Скорость вызова с прокси Proxy 45k вызовов в секунду
                                  Скорость вызова итератора 160k вызовов в секунду

                                  Вызываем функцию

                                   public int ПолучитьЧисло(int число)
                                          {
                                  
                                              return число;
                                          }
                                  

                                  Код такой
                                  // Протестируем скорость вызовов без Proxy
                                              var start = new Date();
                                              let count = 100000;
                                              let result = 0;
                                              for (let i = 0; i < count; i++)
                                                  result += window.CallNetMethod(Id, "ПолучитьЧисло", [1]);
                                  
                                              this.speed = Math.round(count / (new Date().getTime() - start.getTime()) * 1000);
                                        
                                  
                                          // Протестирум это же но через Proxy
                                  
                                              start = new Date();
                                              result = 0;
                                              for (let i = 0; i < count; i++)
                                                  result +=TO.ПолучитьЧисло(1);
                                  
                                              this.speedWithProxy = Math.round(count / (new Date().getTime() - start.getTime()) * 1000);
                                  
                                             // Протестируем скорость вызова итератора
                                              let iter = TO.GetNumbers(count);
                                              start = new Date();
                                              result = 0;
                                              for (let i of iter)
                                                  result += i;
                                  
                                              this.spedCallIterator = Math.round(count / (new Date().getTime() - start.getTime()) * 1000);
                                  
                                              NetObject.DeleteNetObjets(TO, Тестовый, iter);
                                      }
                                  
                                  • +1

                                    Эти цифры говорят только о том, какова скорость вызовов методов .net из TS. Они ничего не говорят ни о том, какова эта скорость в сравнении с межпроцессным транспортом, ни о том, какой оверхер будет в реальном применении.

                                    • 0
                                      Она показывает, что скорость вполне приемлема для большинства задач.
                                      Кроме того в большинстве случаев тебе не нужны циклы, в большинстве случаев тебе нужен некий функционал Net классов. Например можно перенести готовую логику WPF на Angular 2 или Electron.
                                      C http\ws у тебя будет значительно больше работы, чем использовать классы напрямую. Тем более работа с оборудованием ни как не спасет.

                                      Ну для интереса можно вызвать Http сервис и подсчитать. Это несложно. Но, что то мне подсказывает, что межпроцеесоное взаимодействие максимум на 1к вызов в секунду выйдет.
                                      • 0
                                        Она показывает, что скорость вполне приемлема для большинства задач.

                                        А у out-of-process-сервера — неприемлема?

                                        • 0
                                          Я предлагаю еще вариант использования. Есть альтернатива out-of-process-сервера. Чем это плохо,
                                          Для кого то может быть и неприемлема. При этом нужно отдельно держать http\ws сервер.
                                          • 0
                                            Я предлагаю еще вариант использования. Есть альтернатива out-of-process-сервера. Чем это плохо,

                                            Да ничем это не плохо, если это стабильно работает и не требует лишних усилий. Но с моей личной точки зрения, писать в двух экосистемах, если можно обойтись одной — это уже лишние усилия.


                                            При этом нужно отдельно держать http\ws сервер.

                                            Вы правда не знаете других способов межпроцессного взаимодействия, кроме http/ws (и я даже не буду спрашивать, что такое "ws" в этой паре)?

                                            • 0
                                              Угу http/ws это надстройка на Tcp/IP.
                                              Но проблема сериализации, десериализации остается. При этом что HTTP что Вэб сервисы это сериализация через текст. Можно конечно использовать WCF на netNamedPipeBinding, что я часто и делаю? но поверь трудозатраты несоизмеримы с прямым использованием
                                              • 0
                                                Угу http/ws это надстройка на Tcp/IP.

                                                Ну и зачем мне TCIP/IP на одной машине?


                                                Но проблема сериализации, десериализации остается.

                                                А у вас данные между двумя виртуальными машинами совсем без сериализации/десериализации гуляют, да?


                                                Можно конечно использовать WCF на netNamedPipeBinding, что я часто и делаю? но поверь трудозатраты несоизмеримы с прямым использованием

                                                "Прямое использование" — это .net-.net. Да, не вопрос, несоразмеримы. Но то, что сверху — это уже куча трудозатрат, и еще понадобится вложить.

                                                • 0
                                                  Ну там просто копирование в одном процессе.
                                                  Я показал пример, где различия минимальны. Очень близко к .net-.net
                                                  • 0
                                                    Ну там просто копирование в одном процессе.

                                                    Копирование чего, простите?


                                                    Я показал пример, где различия минимальны. Очень близко к .net-.net

                                                    А можно метрику .net-.net в тех же условиях?

                                                    • 0
                                                      Пожалуйста, на первом том примере она будет минимальна, ибо основное время это получение данных с сайта.
                                                      • 0

                                                        "Она будет минимальна" — это ни о чем. Цифры, цифры и еще раз цифры.

                                                        • –1
                                                          У тебя для этого все есть. У меня нет времени.
                                                          • 0

                                                            Тут уже как-то говорили, что не стоит делать утверждения, которые потом "нет времени" доказывать.

                                                            • –1
                                                              Я тебе сказал, что там основное время это получение данных с сайта. Если ты не веришь, то сам и проверь.
                                                              • 0

                                                                … если там основное время — это получение данных с сайта, то накладные расходы на межпроцессное взаимодействие никого уже не волнуют. Что, собственно, и требовалось доказать.

                                                                • –1
                                                                  Кто то выбирает один процесс, а кто то как ты несколько.
                                                                  Что и так было ясно.
                                                                  • 0

                                                                    Вот только у каждого выбора есть своя аргументация. Кто-то аргументирует выбор одного процесса тем, что много накладных расходов… вот только подтвердить это пока не удалось.

                                                                    • 0
                                                                      Я аргументиру это тем, что писать на один процес легче.
                                                                      При этом обработку данных можно вынести в .Net сборку,
                                                                      а там где скорость не критична можно использовать стандартные библиотеки.
                                                                      Есть большой выбор в отличие от твоего подхода. За каждой мелочью премся на сервер.
                                                                      • 0
                                                                        Я аргументиру это тем, что писать на один процес легче.

                                                                        Легче писать в одной экосистеме. А когда вы пишете чудовище франкенштейна, где в каждый момент времени не понятно, в каком контексте выполняется код, и происходит, когда я записываю в свойство — это не легче.


                                                                        (мы всего этого успели наестся еще во времена remoting).


                                                                        Вот я вызвал из клиент-сайда (JS) метод сервер-сайда (.net). Тот создал ConcurrentDictionary, запустил отдельный поток для расчетов, и вернул словарь мне. Отдельный поток продолжает писать в словарь. Внимание, вопрос: когда я буду вызывать методы на словаре на стороне JS, они будут видеть "новое" состояние?


                                                                        Есть большой выбор в отличие от твоего подхода. За каждой мелочью премся на сервер.

                                                                        Это не "мой подход", а тот подход, который вы мне приписываете. Я этого нигде не говорил.

                                                                        • –1
                                                                          Угу чем это отличие от HTTP запроса? Я знаю что за классы я использую.
                                                                          Ну и чем ремотинг от HTTP запроса отличается?
                                                                          Через await и увидит. Сейчас прикручиваю события.

                                                                          Ну а как ты же говоришь о превосходстве out процессов. А значит есть сервер.
                                                                          • 0
                                                                            Угу чем это отличие от HTTP запроса? Я знаю что за классы я использую.
                                                                            Ну и чем ремотинг от HTTP запроса отличается?

                                                                            Это мы пропустим, как не имеющее отношения к делу.


                                                                            Через await и увидит. Сейчас прикручиваю события.

                                                                            В ConcurrentDictionary нет ни async, ни событий. Я спрашиваю про простое dict["abc"].


                                                                            Ну а как ты же говоришь о превосходстве out процессов. А значит есть сервер.

                                                                            Не сервер, а другой процесс. И да, поскольку есть другой процесс, и это эксплицитно, интерфейс меняется с chatty на chunky, поэтому никакого "за каждой мелочью".

                                                                            • 0
                                                                              В ConcurrentDictionary нет ни async, ни событий. Я спрашиваю про простое dict["abc"].

                                                                              Кажется, вы не поняли всего прикола его решения. Нет никакого dict["abc"] на стороне JS! Там делается вызов get_Item("abc"), который прокси-объектом пробрасывается в .NET-код, где и выполняется.

                                                                              • 0

                                                                                Я, к сожалению, понял. И приводит это к еще более chatty-интерфейсу, чем можно было бы сделать, потому что — если я ничего не пропустил — там вообще нельзя вернуть объект с той стороны. Или структуру все-таки можно?

                                                                                • 0

                                                                                  Да вы что! У структуры же могут тоже быть методы! И их может понадобится вызвать!

                                                                                  • 0

                                                                                    Значит, я правильно предположил, и только базовые типы (с потерей, я так понимаю, возможности вызывать методы на них). Кстати, а что со строками?


                                                                                    Зато это объясняет, почему нет сериализации (ну, почти нет). Зато любые утверждения о том, что с этим просто работать после этого однозначно в топку.

                                                                                    • –1
                                                                                      Я же написал в чем отличие
                                                                                      Прежде всего видим главные отличия от C#. Для получения свойства нужно добавить "_"

                                                                                      let Default = Configuration._Default;

                                                                                      Для вызова асинхронного метода нужно добавить ключевое слово async:

                                                                                      let document = await Context.async.OpenAsync(address);

                                                                                      Для вызова дженерик метода, если нельзя вывести типы по параметрам то аргументы указываем в массиве:

                                                                                      let rows = ApiExtensions.QuerySelectorAll([IHtmlTableRowElement], document, rowSelector);

                                                                                      Ну и главное, нужно вручную удалить ссылку на объект со стороны .Net

                                                                                      Строки копируются.
                                                                                      Я никого не заставляю использовать мой продукт, я делюсь опытом.
                                                                                      Я в 1С прекрасно совмещаю как .Net объекты так и 1С. И никаких неудобств мне это не приносит. А здесь в отличие от 1С я могу прикрутить типизацию
                                                                                  • 0
                                                                                    Структуры боксятся и можно вызывать методы наравне со статческими методами, методы дженериков с автовыводом типа. Поддержка параметров по умлчанию, params
                                                                                    • 0
                                                                                      Структуры боксятся

                                                                                      Все? Вообще все?


                                                                                      let price = netCalculator.getPrice();
                                                                                      if (price >= 100)
                                                                                        ...

                                                                                      netCalculator — это объект от .net, с бизнес-логикой внутри. Какого типа price?

                                                                                      • 0
                                                                                        Мы говорим про мою проект. Там доступ к свойствам и методам производится через рефлексию. А в рефлексии все боксится
                                                                                        • 0

                                                                                          … а теперь посмотрите на второй вопрос.

                                                                                          • 0
                                                                                            По твое логике int. Они кстати просто копируются.

                                                                                            А для ссылочных типов на стороне JS нужно вызывать Equals или op_ или compare
                                                                                            • 0
                                                                                              Но на стороне JS нужно вызывать Equals или op_ или compare

                                                                                              То есть price — все-таки не number?

                                                                                              • 0
                                                                                                Ну в Net понятия number. Будет либо int либо Double. Другие типы не поддерживаются JS и нужно их оборачивать через ChangeType
                                                                                                • 0

                                                                                                  Я, вообще-то, про JS говорю. То, что GetPrice возвращает Decimal — это данность. А вот какого типа джаваскриптовая переменная price, в которую вы записали это значение?

                                                                                                  • 0
                                                                                                    Будет объект на стороне Net. Либо можно конвертировать в строку как я это делаю для 1С.
                                                                                                    Сейчас посмотрел в текущей реализации делается так
                                                                                                    if (Тип == typeof(System.Decimal)) return ((Decimal)obj).ToString(CultureInfo.InvariantCulture);
                                                                                                    • 0
                                                                                                      Будет объект на стороне Net.

                                                                                                      С которым нельзя работать, как с числом. Круто, да, очень просто для разработчика на стороне JS.


                                                                                                      Сейчас посмотрел в текущей реализации делается так
                                                                                                      if (Тип == typeof(System.Decimal)) return ((Decimal)obj).ToString(CultureInfo.InvariantCulture);

                                                                                                      … и любая проверка типа на стороне JS радостно говорит "да это ж не число". Да?

                                                                                                      • 0
                                                                                                        Ну что делать если на стороне JS нет понятия decimal/
                                                                                                        Он может либо из строки сделать свой Decimal на примере https://github.com/MikeMcl/decimal.js

                                                                                                        Можно для Decimal делать конвертацию в этот объект.
                                                                                                        Опять же я выдал продукт и собираю мнения, как его улучшить, и нужно ли это вообще
                                                                                                        • +1
                                                                                                          Ну что делать если на стороне JS нет понятия decimal

                                                                                                          Работать в тех терминах, которые в JS есть. А если их нет — по крайней мере, не прикидываться, что это "просто".


                                                                                                          Опять же я выдал продукт и собираю мнения, как его улучшить, и нужно ли это вообще

                                                                                                          Вот вам и говорят, что не нужно.

                                                                                                          • –2
                                                                                                            А кто прикидывается? В чем проблема распарсить строку в объект?

                                                                                                            Про ненужно мне давно известно, только странно, что ты это так доказываешь.
                                                                                                            Я не успеваю работать.
                                                                                                            • 0
                                                                                                              А кто прикидывается? В чем проблема распарсить строку в объект?

                                                                                                              В том, что это лишнее действие, нарушающее, собственно, постулат "работать просто".

                                                                                                              • 0
                                                                                                                А что делать если JS этого не поддерживает?
                                                                                                                Что ты кстати будешь делать через out process?
                                                                                                                • 0
                                                                                                                  А что делать если JS этого не поддерживает?

                                                                                                                  Если не поддерживает, значит, в JS с этим работать неудобно.


                                                                                                                  Что ты кстати будешь делать через out process?

                                                                                                                  Получать данные в тех типах, которые JS поддерживает.

                                                                                                                  • 0
                                                                                                                    Иииии? Но вот данные храняться в Decimal. Что делать?
                                                                                                                    Ну и я передаю в виде строки.
                                                                                                                    • 0
                                                                                                                      Иииии? Но вот данные храняться в Decimal. Что делать?

                                                                                                                      Преобразовывать в семантически понятный JS тип, очевидно. У меня decimal-данные прекрасно летают между двумя машинами в JSON, и ничего.

                                                                                                                      • –1
                                                                                                                        Угу JSON это та же строка. Но вот только Decimal и Double разные вещи.
                                                                                                                        • 0
                                                                                                                          Угу JSON это та же строка.

                                                                                                                          Внезапно, нет.


                                                                                                                          Но вот только Decimal и Double разные вещи.

                                                                                                                          В .net, да. Но в JS[ON] нет ни того, ни другого, есть number.

                                                                                                                          • 0
                                                                                                                            Дааа? а как данные передаются?

                                                                                                                            Угу и как JS сконвертирует число которое не подходит под Double?
                                                                                                                            • 0
                                                                                                                              Дааа? а как данные передаются?

                                                                                                                              В виде строкового представления. Не путайте представление с сообщением.


                                                                                                                              Угу и как JS сконвертирует число которое не подходит под Double?

                                                                                                                              А откуда вы вообще взяли понятие Double? Мне всегда казалось, что в JS есть только number, и будут использоваться его ограничения.

                                                                                                                              • –1
                                                                                                                                Все я прекращаю диалог. Совершенно нет времени, а диалог совсем не конструктивный. Списибо за общение.
                                                                                                                                В CEF есть только Double и Int
                                                                                                                                • 0
                                                                                                                                  В CEF есть только Double и Int

                                                                                                                                  … так это проблемы выбранного вами CEF.

                                                                                                                                  • 0
                                                                                                                                    http://stackoverflow.com/questions/3454965/javascript-decimal-values
                                                                                                                                    • 0

                                                                                                                                      Пичалько. В том смысле, что работать с точными числами в таких условиях — это боль и страх. И, значит, тут придется выкручиваться, очередной раз за счет усложнения кода.

                                                                                                                                    • 0
                                                                                                                                      Если Number поддерживает Decimal, то могу передавать на строну CEF бинарные данные, из CEF преобразовывать в объект со строковым представлением числа и флагом, что это Decimal. На стороне JS парсить по аналогии с Json. Нет проблем.
                                                                                                                                      • 0

                                                                                                                                        Да понятно, что "нет проблем", только каждое такое дополнение — это увеличение кода, который надо написать и поддерживать (что понижает "простоту" решения) и потери в производительности (что снижает привлекательность решения с этой точки зрения).

                                                                                                                                        • 0
                                                                                                                                          Все делается в прокси. И я тебе давал ссылку на https://mikemcl.github.io/decimal.js/
                                                                                                                                          Опять же, все вычисления делаются на стороне Net в моем случае, где этих ограничений нет и я могу использовать Decimal как объект
                                                                                                                                          • 0
                                                                                                                                            Все делается в прокси.

                                                                                                                                            Который тоже надо писать и поддерживать.


                                                                                                                                            Опять же, все вычисления делаются на стороне Net в моем случае

                                                                                                                                            Так я про это с самого начала и говорил: проще все сделать на .net и не возиться.

                                                                                                                                            • 0
                                                                                                                                              Вогт я написал прокси один раз. Зачем мне его поддерживать
                                                                                                                                              Так сделай на линуксе с UI. И покажи нам всем. Я буду тебе только благодарен.
                                                                                                                                              • 0
                                                                                                                                                Вогт я написал прокси один раз. Зачем мне его поддерживать

                                                                                                                                                Потому что нет программы без ошибок, во-первых, и вы никогда не учтете всего с первого раза во-вторых.


                                                                                                                                                Так сделай на линуксе с UI. И покажи нам всем.

                                                                                                                                                Берете asp.net core приложение и открываете в браузере. Enjoy.

                                                                                                                                                • 0
                                                                                                                                                  Ну с этой точки зрения тот же CEF постоянно переписывается. Но есть вещи которые не трогаются годами.

                                                                                                                                                  Иииии. При этом за всеми данными ползать на сервер. Наша песня гарна нова?

                                                                                                                                                  То есть ты не различаешь понятия Декстоп, где мы отвязаны от сервера?

                                                                                                                                                  Я понимаю, что моя разработка ни кому не нужна, но я лично никакой радости не имею переводя wpf приложение на asp.net core. Это вы батенька мазохист. В моем случае мне нужно только переписать код формы, а всю остальную логику перекомпилировать под .Net Core. Учитывая, что NetStandard 2 не загорами, то переделки минимальны.
                                                                                                                                                  • 0
                                                                                                                                                    Ну с этой точки зрения тот же CEF постоянно переписывается. Но есть вещи которые не трогаются годами.

                                                                                                                                                    Для этого сначала надо потратить годы на то, чтобы их написать. Это не так-то просто.


                                                                                                                                                    То есть ты не различаешь понятия Декстоп, где мы отвязаны от сервера?

                                                                                                                                                    Да все я различаю, а еще я оцениваю количество нужных усилий.


                                                                                                                                                    В моем случае мне нужно только переписать код формы, а всю остальную логику перекомпилировать под .Net Core.

                                                                                                                                                    Дадада, конечно, переписать код формы с WPF на JS — это совершенно тривиальное занятие. А маппинг из JS на .net core — так и вовсе волшебным образом появился.


                                                                                                                                                    "Только", да.

                                                                                                                                                    • 0
                                                                                                                                                      Там кода прокси максимум строк 100. Это далеко не годы.
                                                                                                                                                      Ты даже не знаком с моей разработкой. Но действуешь по принципу «Не читал, но осуждаю»

                                                                                                                                                      Я тебе показал, что код на TS мало отличается от кода на C#. Мало того можно нагенерить ds.ts и наслаждаться Intellisense

                                                                                                                                                      Но опять же хозяин барин. Я же в начале статьи написал, что моя разработка мало кому интересна. Ты яркое подтверждение моих слов.
                                                                                                                                                      • 0
                                                                                                                                                        Там кода прокси максимум строк 100.

                                                                                                                                                        Это пока не начали всплывать вещи типа "а как сконвертировать decimal", "а что делать с событиями", "а как передать делегат", "а как передать объект".


                                                                                                                                                        Я тебе показал, что код на TS мало отличается от кода на C#.

                                                                                                                                                        Мы уже выяснили, что нет: как минимум, нет автоматического управления памятью (которое есть и в TS, и в C#), нельзя передавать объекты, и так далее.


                                                                                                                                                        А уж в WPF-то вообще не C#-ный код, там биндинги и прочее декларативное счастье. Кстати, для того, чтобы оно работало, нужны события...

                                                                                                                                                        • 0
                                                                                                                                                          Как передать делегат и объект написано. Ты не читаешь.
                                                                                                                                                          События мало отличаются от асинхронных вызовов.

                                                                                                                                                          Ну ручное управление мало отличаются от using ты и в C# должен своевременно закрыть ресурсы.

                                                                                                                                                          События я как раз пишу. Но ты мне не даешь закончить. Ты хоть работаешь?
                                                                                                                                                          • +1
                                                                                                                                                            Как передать делегат и объект написано. Ты не читаешь.

                                                                                                                                                            Ну да, написано: передача объектов не поддерживается. Думаю, что и с делегатами то же самое.


                                                                                                                                                            Ну ручное управление мало отличаются от using ты и в C# должен своевременно закрыть ресурсы.

                                                                                                                                                            Ээээ, серьезно? А то, что ресурсов, требующих using, намного меньше, чем обычных объектов, вы не в курсе? Я не пишу using для строк, я не пишу using для массивов и вообще коллекций — да чего там, я реже пишу using, чем не пишу.


                                                                                                                                                            События я как раз пишу. Но ты мне не даешь закончить. Ты хоть работаешь?

                                                                                                                                                            Конечно, нет. У меня вечер, зачем мне работать?

                                                                                                                                                            • 0
                                                                                                                                                              Написано, что не поддерживается передача JS объектов. Но название статьи
                                                                                                                                                              «TypeScript использование классов .Net Core „
                                                                                                                                                              Так, что ты пиши правильно. В JS нет понятия делегатов. Там все свойства и методы тоже.

                                                                                                                                                              А, днем чего делал. Заметь мы скоро рекорд побъем по количеству сообщений.
                                                                                                                                                              Дай мне написать события.
                                                                                                                                                              • 0
                                                                                                                                                                Написано, что не поддерживается передача JS объектов. Но название статьи
                                                                                                                                                                «TypeScript использование классов .Net Core „

                                                                                                                                                                Понимаете ли, в чем дело… под использованием люди разные вещи понимают. И когда я не могу собрать на лету анонимный объект, чтобы запихнуть его в, скажем, логгер, или в транспорт, или куда-то еще — это ограничение использования. И когда я не могу получить структуру — это тоже ограничение использования. И так далее, далее, далее. Ваш прокси на 100 строк потому и укладывается в 100 строк, что не дает привычных возможностей — только те, которых лично вам, как вы думаете, достаточно.


                                                                                                                                                                В JS нет понятия делегатов.

                                                                                                                                                                Правда? А коллбек-функция — это что?


                                                                                                                                                                Дай мне написать события.

                                                                                                                                                                Да я вас вроде за руку и не держу...

                                                                                                                                                                • 0
                                                                                                                                                                  Это функция. Делегат это чисто C# понятие. Вернее правильнее даже мультиделегат.
                                                                                                                                                                  Если ты посмотришь на Proxy, то заметишь, что есть get, set и apple. А вот вызова как метода объекта нет.
                                                                                                                                                                  То есть объект может быть функцией и иметь свойства. Свойства могут быть функциями.

                                                                                                                                                                  Еще раз. Я завожусь и не могу остановиться пока не отвечу.
                                                                                                                                                                  А вопросы ну никакие, но ничего не могу с собой поделать. Это по сути шизофрения. Но где то она помогает, а где то как с тобой мешает.
                                                                                                                                                                  • 0
                                                                                                                                                                    Делегат это чисто C# понятие.

                                                                                                                                                                    На самом деле, нет — как минимум оно используется во всем .net. Но не суть, заменим делегат на колбек. Колбеки передавать можно? А лямбда-выражения?

                                                                                                                                                                    • 0
                                                                                                                                                                      Молодец. Прошу прощения неправильно высказался.

                                                                                                                                                                      Это называется JS функция. После разговора с тобой у меня есть желание на все наплевать и прекратить мои мучения. Наверное не будет.
                                                                                                                                                                      Зачем? Кому это нужно? Одни минуса. Немного карму подняли и плюсов дали. Огромное спасибо за это коллегам.

                                                                                                                                                                      Конечно я не брошу и по инерции сделаю и поддерку объектов и методов, для начала только на время вызова функции.

                                                                                                                                                                      • 0
                                                                                                                                                                        Это называется JS функция.

                                                                                                                                                                        Лямбда-выражения? Которые Expression<Func...>? Нет, совсем нет.

                                                                                                                                                                        • 0
                                                                                                                                                                          А при чем тут деревья выражений?
                                                                                                                                                                          Ладно пошел я спать. И тебе советую. Прошу извинить если не буду больше отвечать. Море дел. Спокойной ночи?
                                                                                                                                                                          • 0
                                                                                                                                                                            А при чем тут деревья выражений?

                                                                                                                                                                            При том, что я про них и говорил, когда спрашивал про лямбда-выражения. Когда у тебя ощутимая часть бизнес-кода на них построена — как-то поневоле задумываешься, можно ли их использовать в предлагаемом новом инструменте.

                                                                                                                                                                            • 0
                                                                                                                                                                              Да уж не далеко я ушел. Деревья выражений и лямбда выражения это не деревья выражений

                                                                                                                                                                              Лямбда-выражения

                                                                                                                                                                              Лямбда-выражение — это анонимная функция, с помощью которой можно создавать типы делегатов или деревьев выражений. С помощью лямбда-выражений можно писать локальные функции, которые можно передавать в качестве аргументов или возвращать в качестве значений из вызовов функций. Лямбда-выражения особенно полезны при написании выражений запросов LINQ.


                                                                                                                                                                              Класс Expression

                                                                                                                                                                              Дерево выражений является представлением данных в памяти, лямбда-выражения. Дерево выражений делает структуру лямбда-выражения прозрачной и явной. Можно взаимодействовать с данными в дерево выражения, так же, как и с любой другой структурой данных.

                                                                                                                                                                              Возможность использовать выражения как структуры данных включает для интерфейсов API получение кода пользователя в формате, который можно проверить, преобразования и обрабатываются особым образом. Например LINQ to SQL реализацию доступа к данным использует это средство для переводы деревьев выражения в инструкции Transact-SQL, которые можно оценить в базе данных.

                                                                                                                                                                              Многие стандартные операторы, определенные в Queryable класса имеют один или несколько параметров типа Expression.


                                                                                                                                                                              Давай спокойной ночи.
                                                                                                                                                                              • 0

                                                                                                                                                                                Лямбда-выражения — это синтаксический сахар, который позволяет получить на выходе как функцию, так и дерево выражений. Меня интересовала вторая ипостась (потому что про первую мы уже выяснили, что ее нет). Когда я пишу типичный код productRepository.Matching(p => p.Cost < 15), я хочу так дальше и писать, а не думать, как мне извратиться в JS/TS.


                                                                                                                                                                                Впрочем, у меня вообще много монадического кода типа


                                                                                                                                                                                message
                                                                                                                                                                                .If(c => m?.Credentials?.Certificate?.IsValid)
                                                                                                                                                                                .With(m => m.Registration)
                                                                                                                                                                                .CheckNull(() => new InvalidOperationException())
                                                                                                                                                                                .Map<Client>()
                                                                                                                                                                                .Select(c => c.Secrets)
                                                                                                                                                                                .Do(Add)

                                                                                                                                                                                А теперь, значит, выставим message как прокси-объект в TS ииии понеслась.

                                                                                                                                                                                  • 0

                                                                                                                                                                                    Да понятно, что можно то, можно это, можно что-нибудь еще. Но каждое такое "можно" добавляет сложности в ваш прокси (о чем я, собственно, и говорил выше).


                                                                                                                                                                                    Более того, вот возьмем мой пример, первый вызов (я убрал null-coalescing, чтобы не мешал), и перенесем на сторону JS/TS:


                                                                                                                                                                                    message.If(m => m.Credentials.Certificate.IsValid)

                                                                                                                                                                                    message — это объект .net (через прокси), If — extension method на этом объекте. Предположим, что вы уже умеете обрабатывать extension methods (а умеете ли?), и развернем это в статический вызов:


                                                                                                                                                                                    Maybe.If(message, m => m.Credentials.Certificate.IsValid)

                                                                                                                                                                                    Окей. Вызов статического метода (.net), первый параметр — объект (.net), второй — анонимная функция (JS). Вызываем метод, первый параметр разворачиваем из-под прокси, для второго создаем прокси (нам же нужно передать что-то на сторону .net) к JS-функции. If внутри себя что-то делает (проверку на null, на самом деле) и вызывает переданную ему функцию — то есть, опять наш прокси — передав ему все тот же объект. Тот, в свою очередь, вызывает функцию из-под прокси, передав ей в качестве параметра прокси от .net-объекта (хорошо, если тот же самый, что раньше, а то ведь может и новый создать).


                                                                                                                                                                                    Ура, мы дошли до внутренностей анонимной функции (для этого дважды пересекли границу CEF, ага). Первое, что мы видим — обращение к свойству .net-объекта, а это значит, что мы снова вызываем прокси, разворачиваем это свойство, вызываем свойство на .net-объекте, получаем ответ, заворачиваем в (новый) прокси, возвращаем обратно… чтобы повторить еще дважды. Результат этого — bool — мы возвращаем из функции, оно попадает в прокси функции, потом в If, и тот уже возвращает исходный объект (или null), который в свою очередь возвращается в JS в виде прокси.


                                                                                                                                                                                    Одна строчка кода. От пяти до семи прокси создано (в зависимости от того, умеете ли вы понимать, что для возвращенного объекта уже был прокси) и что-то порядка семи пересечений границы CEF (считал на глаз). Одна строчка кода.


                                                                                                                                                                                    И эти люди говорят нам за перформанс.

                                                                                                                                                                                    • 0
                                                                                                                                                                                      Давай я пока поддержку Эвентов допишу. Немного осталось. А потом уже за JS объекты возьмусь. Ты сможешь протестировать и дать рекомендации.

                                                                                                                                                                                      Там под Net надо свой Linq делать с автоосвобождением ссылок.
                                                                                                                                                                                      Сейчас не готов это обсуждать. Не начем. Буду делать учту твои доводы.
                                                                                                                                                                                      • 0
                                                                                                                                                                                        Там под Net надо свой Linq делать с автоосвобождением ссылок.

                                                                                                                                                                                        Вот-вот. Сто строк, ага.

                                                                                                                                                                                        • 0
                                                                                                                                                                                          Нет это не Proxy.
                                                                                                                                                                                          Ты хочешь столько, сколько я один сделать не могу. Но я могу использовать ScriptingApi? могу динамически создавать сборки. Вариантов куча.
                                                                                                                                                                                          Еще раз никто же тебе не запрещает писать на C# и использовать нормальный Linq.
                                                                                                                                                                                          • 0
                                                                                                                                                                                            Еще раз никто же тебе не запрещает писать на C# и использовать нормальный Linq.

                                                                                                                                                                                            Бинго, я про это с самого начала и говорю: намного проще писать на C# и использовать нормальную функциональность.

                                                                                                                                                                                            • 0
                                                                                                                                                                                              А кто твой код то будет вызывать из браузера?
                                                                                                                                                                                              Он сам внедрится?
                                                                                                                                                                                              • –1

                                                                                                                                                                                                Вы не поверите: браузер. Люди прекрасно писали интерактивные приложения до появления JS, в чистом сервер-сайде.


                                                                                                                                                                                                Впрочем, это сейчас неудобно, спорить не буду. Но я могу взять готовый клиент-сайд, их сейчас тысячи, натравить его на "стандартный" REST — и получить типовое приложение, механизмы работы которого понятны и предсказуемы.

                                                                                                                                                                                                • –1
                                                                                                                                                                                                  Я разве запрещаю. Делай как хочешь. А кому то может и мой подход понравится. На вкус и цвет товарищей нет
                                                                                                                                                                                  • 0
                                                                                                                                                                                    Ну а вообще так как мы можем получить итератор то можем использовать для этих целей TS
                                                                                                                                                                                    LinQ for TypeScript

                                                                                                                                                                                    import { List } from 'linqts';
                                                                                                                                                                                    
                                                                                                                                                                                    let arr = new List<number>([1,2,3,4,5])
                                                                                                                                                                                        .Where(x => x > 3)
                                                                                                                                                                                        .Select(y => y * 2)
                                                                                                                                                                                        .ToArray(); // > [8, 10]
                                                                                                                                                                                    
                                                                                                                                                                                    let query = people.Join(pets,
                                                                                                                                                                                        person => person,
                                                                                                                                                                                        pet => pet.Owner,
                                                                                                                                                                                        (person, pet) =>
                                                                                                                                                                                            ({ OwnerName: person.Name, Pet: pet.Name }));
                                                                                                                                                                                    


                                                                                                                                                                                    И есть еще куча аналогов на TS.

                                                                                                                                                                                    Скорость выборки итератора порядк 170к в секунду.
                                                                                                                                                                                    Здесь лучше использовать гибридный подход
                                                                                                                                                                                    • 0
                                                                                                                                                                                      Ну а вообще так как мы можем получить итератор то можем использовать для этих целей TS (LinQ for TypeScript)

                                                                                                                                                                                      Не-а.


                                                                                                                                                                                      Во-первых, не везде, где нужны деревья, есть итераторы (первый же пример — маппинг).


                                                                                                                                                                                      Во-вторых, предлагать использовать клиентскую итерацию поверх данных из БД — это, конечно, живо. Тривиальный джойн с фильтрацией — и вместо одной строчки (причем неполной) мы вытащим из БД пару (сотен) тысяч, в полную ширину.


                                                                                                                                                                                      Спасибо, нет.

                                                                                                                                                                                      • 0
                                                                                                                                                                                        Я вообще то не предлагаю все делать на стороне JS. Ты также можешь написать свои Dll которая может подгружаться по web.
                                                                                                                                                                                        Нет смысла все писать на JS/ Вся прелесть в использовании сборок .Net из JS
                                                                                                                                                                                        • 0
                                                                                                                                                                                          Я вообще то не предлагаю все делать на стороне JS.

                                                                                                                                                                                          Ну то есть фраза "получить итератор и использовать TS" мне показалась, ага.

                                                                                                                                                                                          • 0
                                                                                                                                                                                            Можно использовать и итератор. Все зависит от ситуации. У тебя есть выбор где это делать В сборке или в JS.
                                                                                                                                                                                            • 0

                                                                                                                                                                                              У меня есть только иллюзия выбора, потому что в любом разумном сценарии такие операции надо переносить в сборку. Что, собственно, и приводит к ситуации "все сделать в .net", о которой я говорил раньше.

                                                                                                                                                                                              • 0
                                                                                                                                                                                                И использовать из JS. Код то сам не вызовется.
                                                                                                                                                                                                • 0

                                                                                                                                                                                                  … это если мне зачем-то вообще сдался JS.

                                                                                                                                                                                                  • –1
                                                                                                                                                                                                    Молодец!!! Повеселил. Ты хоть название то статьи вспомни.
                                                                                                                                    • –1
                                                                                                                                      Вот когда кажется
                                                                                                                                      https://learn.javascript.ru/number
                                                                                                                                      Все числа в JavaScript, как целые так и дробные, имеют тип Number и хранятся в 64-битном формате IEEE-754, также известном как «double precision».

                                                                                                                                      https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Number

                                                                                                                                      Number.isSafeInteger()  Определяет, является ли переданное значение безопасным целым числом (числом в диапазоне от -(2:53 — 1) до 2^53 — 1).

                                                                                                                                      https://msdn.microsoft.com/ru-ru/library/364x0z75.aspx

                                                                                                                                      Ключевое слово decimal обозначает 128-разрядный тип данных. По сравнению с типами данных с плавающей запятой, диапазон значений типа decimal меньше, а точность выше, благодаря чему этот тип подходит для финансовых расчетов. В следующей таблице представлен приблизительный диапазон значений и точность для типа decimal

                                                                                                                                      • 0

                                                                                                                                        … правильно же казалось: есть тип number, ограничения которого вы и озвучили.

                                                                                                                                        • 0
                                                                                                                                          По сути это Double. Посмотри на максимальное целое значение. Несмотря на то, что число 64 разрядное. Но реально в CEF два вида int и Double.
                                                                                                                                          Int64 приводится к Double. CEF это по сути Google Chrome
                                                                                                                                          • 0
                                                                                                                                            Но реально в CEF два вида int и Double.

                                                                                                                                            … личные детали реализации CEF.


                                                                                                                                            Впрочем, это тоже не важно. Ну да, мы нашли непредставимое в JS значение. Это усложняет задачу, не упрощает ее.

                                                                                                                              • 0
                                                                                                                                Кстати говоря о out process мы то говорим о поддержке браузером протоколов.
                                                                                                                                А в нем только HTTP. Могу завтра проверить скрорсть передачи и получении числа.
                                                                                                                                • 0
                                                                                                                                  Кстати говоря о out process мы то говорим о поддержке браузером протоколов.

                                                                                                                                  Это вы говорите только о браузере. Но если мы говорим о браузере, то ваше решение неприменимо вовсе, потому что оно, как мы помним, не браузерное.


                                                                                                                                  А в нем только HTTP.

                                                                                                                                  Это, кстати, неправда.

                                                                                                                                  • 0
                                                                                                                                    Как это не браузерное? Что такое по твоему CEF?

                                                                                                                                    Ну говоря о неправде нужно давать ссылки. Мне ведь тоже интересно, что нон поддерживает.
                                                                                                                                    • 0
                                                                                                                                      Как это не браузерное? Что такое по твоему CEF?

                                                                                                                                      "The Chromium Embedded Framework (CEF) is a simple framework for embedding Chromium-based browsers in other applications."


                                                                                                                                      Ну говоря о неправде нужно давать ссылки. Мне ведь тоже интересно, что нон поддерживает.

                                                                                                                                      Как минимум вебсокеты поддерживаются современными браузерами. Обычно.

                                                                                                                                      • 0
                                                                                                                                        То есть тебе такое слово как browsers ни о чем не говорит?

                                                                                                                                        Так скажем, что Web сокеты не далеко ушли от HTTP. Так на чем меряем скорость?
                                                                                                                                        Возьму ASP.NET Core, Angular 2, SignalR для чайников

                                                                                                                                        Там и тот и другой вариант можно использовать
                                                                                                                                        • 0
                                                                                                                                          То есть тебе такое слово как browsers ни о чем не говорит?

                                                                                                                                          Я еще немножко умею читать контекст, и отличаю embedded browser от обычного браузера. В embedded browser я не ограничен HTTP, мне доступен любой транспорт, на который мне хватило таланта его написать.


                                                                                                                                          Так скажем, что Web сокеты не далеко ушли от HTTP.

                                                                                                                                          Безосновательное утверждение, прямо скажем. На множестве маленьких сообщений (а именно это происходит в UI обычно) вебсокеты могут выигрывать до десяти раз.

                                                                                                                                          • 0
                                                                                                                                            Ны дык он и создан для Декстопа. Используй любые протоколы. И давай сравним их по скорости и удобству использования. На Proxy кстати теряется процентов 30. Но они удобны.

                                                                                                                                            Завтра напишу на await цикл
                                                                                                                                            Релиз TypeScript 2.1

                                                                                                                                            и посмотрим.

                                                                                                                                            Как ты считаешь, кто победит ws или мой JS-CEF-NET
                                                                                                                                            • 0
                                                                                                                                              На Proxy кстати теряется процентов 30. Но они удобны.

                                                                                                                                              Мы уже обсуждали "удобство" вашего решения, и вы меня не убедили.


                                                                                                                                              Как ты считаешь, кто победит ws или мой JS-CEF-NET

                                                                                                                                              В каком соревновании?

                                                                                                                                              • 0
                                                                                                                                                Если честно не собираюсь я тебя ни в чем убеждать. Просто я завожусь, а потом не могу уснуть итд. Понятно, что ты меня тролишь. Но это могя разработка, мое детище, моя кровинка. И конечно я её защищаю.

                                                                                                                                                А насчет соревнования так это количество вызовов в секунду.
                                                                                                                                                Так как мы не используем прокси, твой ws должен выдать не меньше 60к вызовов в секунду.