.Net Core, AppDomain, WCF, RPC маршалинг по Tcp/Ip свой вело
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 19.02.17 14:30
Оценка:
Написал статью .Net Core, AppDomain, WCF, RPC маршалинг по Tcp/Ip свой велосипед

В ней подробно рассказывается как создавать удаленные объекты и вызывать их методы.

Само решение очень близко с COM out process взаимодействием на IDispatch.
Помню с удовольствием разбирался с внутренностями TSocketConnection.

Но, в отличие от Idispatch, используется перегрузка методов и операторов, вызов Generic методов с выводом типов или с заданием Generic аргументов.
Поддержка методов расширений для классов, находящихся в одной сборке и для Linq методов.

Также поддержка асинхронных методов и подписка на события, ref и out параметры, доступ по индексу [], поддержка итераторов в foreach.

В отличии от Web Api, не нужно писать специально серверный код Controller, Hub ы.
Это близко к AppDomain c Remouting но, в отличие от Remoting, каждый класс является аналогом MarshalByRefObject. То есть, мы можем создать любой объект на стороне сервера и вернуть ссылку на него (некоторые языки из чисел поддерживают только double).
При вызове методов, напрямую сериализуются параметры только следующих типов: числа, строки, дата, Guid и byte[]. Для остальных типов нужно их создать на стороне сервера, а в параметрах методов уже передаются ссылки на них.

и солнце б утром не вставало, когда бы не было меня
Отредактировано 06.03.2017 7:20 Serginio1 . Предыдущая версия . Еще …
Отредактировано 03.03.2017 17:28 Serginio1 . Предыдущая версия .
Отредактировано 20.02.2017 7:19 Serginio1 . Предыдущая версия .
Re: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 20.02.17 13:19
Оценка:
Здравствуйте, Serginio1, Вы писали:

Вобщем сделал на Tcp/IP

Но скорость вызова чуть больше 2000 вызовов в секунду. Даже не знаю это много или мало?


Вот клиент
  public class AutoWrapClient : DynamicObject
    {
       public int Target;
        IPEndPoint IpEndpoint;

        public AutoWrapClient(int Target,IPEndPoint IpEndpoint)
        {
            //  IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Parse(АдресСервера), порт);
            this.Target = Target;
            this.IpEndpoint = IpEndpoint;


        }
        // вызов метода

        static public string LastError;

       public static dynamic GetProxy(string ServerAddres, int port)
        {

              IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Parse(ServerAddres), port);
            return new AutoWrapClient(0, ipEndpoint);

        }
        private BinaryReader SendMessage(MemoryStream stream)
        {

            using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            { client.Connect(IpEndpoint);
                using (var ns = new NetworkStream(client))
                {
                    stream.Position = 0;
                    ns.Write(BitConverter.GetBytes((Int32)stream.Length), 0, 4);
                    stream.CopyTo(ns);

                    using (var br = new BinaryReader(ns))
                    {
                        var streamSize = br.ReadInt32();

                        var res = br.ReadBytes(streamSize);

                        var ms = new MemoryStream(res);
                        ms.Position = 0;
                        return new BinaryReader(ms);
                    }

            }
            }
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            result = null;

            var ms = new MemoryStream();
            var bw = new BinaryWriter(ms);

            bw.Write((byte)CallMethod.CallFunc);
            bw.Write(Target);
            bw.Write(binder.Name);
            bw.Write(args.Length);

            foreach (var arg in args)
                WorkVariants.WriteObject(arg, bw);

            bw.Flush();

          var res= SendMessage(ms);

            var resRun = res.ReadBoolean();
            var returnValue = WorkVariants.GetObject(res, IpEndpoint);
            if (!resRun)
            {
                if (returnValue != null && returnValue.GetType() == typeof(string))
                    LastError = (string)returnValue;


                return false;
            }

            result = returnValue;
            //  Error=AutoWrap.СообщитьОбОшибке("не найден дженерик тип "+ИмяМетода);
            return true;


        }
    }



И вызов

 Console.OutputEncoding = System.Text.Encoding.UTF8;

        //Process.Start
        Console.WriteLine("Hello Client!");

        var wrap = Client.AutoWrapClient.GetProxy("127.0.0.1", 6891);

        int res = wrap.ReturnParam(3);
        Console.WriteLine(res);

        string str = wrap.ReturnParam("Hello"); // Возвращает параметр 
        Console.WriteLine(str);
        Console.WriteLine(wrap.ReturnParam(3.14));
        Console.WriteLine(wrap.ReturnParam(DateTime.Now));

        decimal dc = 678.89M;
        Console.WriteLine(dc);
        var stopWatch = new System.Diagnostics.Stopwatch();
        int count = 0;
        stopWatch.Start();
        for (int i = 0; i < 10000; i++)
        {
            count += wrap.ReturnParam(i);

        }

        stopWatch.Stop();
        var ts = stopWatch.Elapsed;
        var elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds,
   ts.Milliseconds / 10, 0);

        Console.WriteLine(count);
        Console.WriteLine(elapsedTime);
        Console.ReadLine();
и солнце б утром не вставало, когда бы не было меня
Отредактировано 21.02.2017 7:11 Serginio1 . Предыдущая версия .
Re: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 21.02.17 09:01
Оценка:
Здравствуйте, Serginio1, Вы писали:

Ну судя по огромному количеству отзывов это осбо не нужно.

Пока реализовал такие вызовы

var wrap = Client.AutoWrapClient.GetProxy("127.0.0.1", 6891);

//ReturnParam просто возвращает переданный параметр
// Через него проверим отправку и возврат результата

        int res = wrap.ReturnParam(3);
        Console.WriteLine(res);

        string str = wrap.ReturnParam("Привет");
        Console.WriteLine(str);
        Console.WriteLine(wrap.ReturnParam(3.14));
        Console.WriteLine(wrap.ReturnParam(DateTime.Now));

        decimal dc = 678.89M;
        Console.WriteLine(dc);

        var ba = new byte[10];
        for (int i = 0; i < ba.Length; i++)
        {
            ba[i]=(byte)i;

        }

        byte[] baRes = wrap.ReturnParam(ba);
        for (int i = 0; i < ba.Length; i++)
        {
            Console.Write(i+",");

        }

        Console.WriteLine("");

      

// Загрузим стороннюю сборку и получим из неё тип
// Сборка должна быть в директории сервера

        var Тестовый = wrap.Тип("TestDllForCoreClr.Тестовый", "TestDll");
// На основании типа создадим объект
        var TO = wrap.New(Тестовый,"Свойство из Конструктора");

// Получим свойство объекта
        Console.WriteLine("Свойство Объекта " + TO.СвойствоОбъекта);

        var EO = TO.ПолучитьExpandoObject();
        Console.WriteLine("Свойство ExpandoObject Имя "+EO.Имя);
        Console.WriteLine("Свойство ExpandoObject Число "+EO.Число);

           int rs = TO.ПолучитьЧисло(89);
        count = 0;
        stopWatch.Restart();
        for (int i = 0; i < 1000; i++)
        {
            count += TO.ПолучитьЧисло(i);

        }

        stopWatch.Stop();



То есть получаем реальный RPC/
Пока сериализуются напрямую

public class WorkVariants
    {
        internal static Dictionary<Type, EnumVar> СоответствиеТипов;
        
        static WorkVariants()
        {

            СоответствиеТипов = new Dictionary<Type, EnumVar>()
            { 
                { typeof(Int16),EnumVar.VTYPE_I2 },
                {typeof(Int32),EnumVar.VTYPE_I4 },
                {typeof(float),EnumVar.VTYPE_R4 },
                {typeof(double),EnumVar.VTYPE_R8 },
                {typeof(bool),EnumVar.VTYPE_BOOL },
                {typeof(sbyte),EnumVar.VTYPE_I1 },
                {typeof(byte),EnumVar.VTYPE_UI1 },
                {typeof(UInt16),EnumVar.VTYPE_UI2},
                {typeof(UInt32),EnumVar.VTYPE_UI4},
                {typeof(Int64),EnumVar.VTYPE_I8},
                {typeof(UInt64),EnumVar.VTYPE_UI8},
                {typeof(string),EnumVar.VTYPE_PWSTR},
                {typeof(byte[]),EnumVar.VTYPE_BLOB},
                {typeof(DateTime),EnumVar.VTYPE_DATE},
                {typeof(AutoWrapClient),EnumVar.VTYPE_AutoWrap}//,
             //   {typeof(AutoWrap),EnumVar.VTYPE_JSObject}
            };


        }

     public static DateTime ReadDateTime(BinaryReader stream)
        {
            long nVal = stream.ReadInt64();
            //get 64bit binary
            return DateTime.FromBinary(nVal);


        }

        public static void WriteDateTime(DateTime value,BinaryWriter stream)
        {
            long nVal = value.ToBinary();
            //get 64bit binary
             stream.Write(nVal);


        }
        public static byte[] ReadByteArray(BinaryReader stream)
        {
            var length = stream.ReadInt32();
            return stream.ReadBytes(length);

        }
      public static  object GetObject(BinaryReader stream, IPEndPoint IpEndpoint)
        {
            
            EnumVar тип =(EnumVar)stream.ReadByte();

            switch (тип)
            {
                case EnumVar.VTYPE_EMPTY:
                case EnumVar.VTYPE_NULL: return null;
                case EnumVar.VTYPE_I2: return stream.ReadInt16();
                case EnumVar.VTYPE_I4: return stream.ReadInt32();
                case EnumVar.VTYPE_R4: return stream.ReadSingle();
                case EnumVar.VTYPE_R8: return stream.ReadDouble();
                case EnumVar.VTYPE_BOOL:return stream.ReadBoolean();
                case EnumVar.VTYPE_I1: return stream.ReadSByte();
                case EnumVar.VTYPE_UI1: return stream.ReadByte();
                case EnumVar.VTYPE_UI2: return stream.ReadUInt16();

                case EnumVar.VTYPE_UI4: return stream.ReadUInt32();

                case EnumVar.VTYPE_I8: return stream.ReadInt64();
                case EnumVar.VTYPE_UI8: return stream.ReadUInt64();
                case EnumVar.VTYPE_PWSTR:

                    var str= stream.ReadString();

                    return str;

                case EnumVar.VTYPE_BLOB:
                                      
                    return ReadByteArray(stream);
                case EnumVar.VTYPE_DATE:
                   
                    return ReadDateTime(stream);

                case EnumVar.VTYPE_AutoWrap:
                        var Target= stream.ReadInt32();
                        var AW = new AutoWrapClient(Target, IpEndpoint);


                    return AW;
            }
            return null;
            }


    
        public static bool WriteObject(object Объект, BinaryWriter stream)
        {

            

            if (Объект == null)
            {

                stream.Write((Int16)EnumVar.VTYPE_NULL);
                stream.Write((Int32)0);
                return true;

            }


            EnumVar type;

            var res = СоответствиеТипов.TryGetValue(Объект.GetType(), out type);

            if (!res) return false;


            stream.Write((byte)type);
            switch (type)
            {
                case EnumVar.VTYPE_I2:  stream.Write((Int16) Объект); break;
                case EnumVar.VTYPE_I4: stream.Write((Int32)Объект); break;
                case EnumVar.VTYPE_R4: stream.Write((float)Объект); break;
                case EnumVar.VTYPE_R8: stream.Write((double)Объект); break;
                case EnumVar.VTYPE_BOOL: stream.Write((bool)Объект); break;
                case EnumVar.VTYPE_I1:  stream.Write((sbyte)Объект); break;
                case EnumVar.VTYPE_UI1: stream.Write((byte)Объект); break;
                case EnumVar.VTYPE_UI2: stream.Write((UInt16)Объект); break;

                case EnumVar.VTYPE_UI4: stream.Write((UInt32)Объект); break;

                case EnumVar.VTYPE_I8: stream.Write((Int64)Объект); break;
                case EnumVar.VTYPE_UI8: stream.Write((UInt64)Объект); break;
                case EnumVar.VTYPE_PWSTR: stream.Write((string)Объект); break;

                case EnumVar.VTYPE_BLOB: stream.Write((byte[])Объект); break;
                case EnumVar.VTYPE_DATE: WriteDateTime((DateTime)Объект, stream);  break;
                case EnumVar.VTYPE_AutoWrap:
                    // УстановитьСтрокуВIntPtr(((AutoWrap)Объект).ПолучитьСсылку(), Элемент);
                    // Marshal.WriteInt16(текПоз, (Int16)EnumVar.VTYPE_PWSTR);
                    stream.Write(((AutoWrapClient)Объект).Target);
                    break;
                    
            }
            return true;
        }

    }


Для ускорения можно вручную сериализовать и десериализовать в byte[]

Буду рад любым идеям и критике
и солнце б утром не вставало, когда бы не было меня
Re[2]: .Net Core, AppDomain, RPC свой велосипед
От: Tom Россия http://www.RSDN.ru
Дата: 21.02.17 10:22
Оценка:
S>Но скорость вызова чуть больше 2000 вызовов в секунду. Даже не знаю это много или мало?
Это настолько неприлично мало что не стоило писать вообще.
Народная мудрось
всем все никому ничего(с).
Re[2]: .Net Core, AppDomain, RPC свой велосипед
От: Tom Россия http://www.RSDN.ru
Дата: 21.02.17 10:23
Оценка:
S>Ну судя по огромному количеству отзывов это осбо не нужно.
Сорри но это жесточайший треш, чем вам веб апи не подошёл?
Народная мудрось
всем все никому ничего(с).
Re[3]: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 21.02.17 10:34
Оценка:
Здравствуйте, Tom, Вы писали:

S>>Но скорость вызова чуть больше 2000 вызовов в секунду. Даже не знаю это много или мало?

Tom>Это настолько неприлично мало что не стоило писать вообще.

А можно поподробнее. Рядом пишут http://rsdn.org/forum/network/6704452.1
Автор: Mr.Delphist
Дата: 21.02.17

2000 вызовов в секунду это 2 вызова каждую миллисекунду, т.е. каждый вызов по 500 микросекунд. Почему Вы считаете, что в диалоговом режиме (вопрос-ответ) TCP/IP должен дать больше? Ведь латентность ОС на процесс и так измеряется в десятках миллисекунд.

и солнце б утром не вставало, когда бы не было меня
Re[3]: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 21.02.17 10:36
Оценка:
Здравствуйте, Tom, Вы писали:

S>>Ну судя по огромному количеству отзывов это осбо не нужно.

Tom>Сорри но это жесточайший треш, чем вам веб апи не подошёл?

А в чем треш? То есть RPC(Remoting),WCF это не треш?

Тот же COM out server тоже треш?

И кстати сколько выдает веб апи вызовов в секунду?

Еще раз это замена AppDomain и Remotig. Они то надеюсь не треш?
и солнце б утром не вставало, когда бы не было меня
Отредактировано 21.02.2017 10:39 Serginio1 . Предыдущая версия . Еще …
Отредактировано 21.02.2017 10:38 Serginio1 . Предыдущая версия .
Отредактировано 21.02.2017 10:37 Serginio1 . Предыдущая версия .
Re[4]: .Net Core, AppDomain, RPC свой велосипед
От: Tom Россия http://www.RSDN.ru
Дата: 21.02.17 10:57
Оценка: +1
S> А в чем треш? То есть RPC(Remoting),WCF это не треш?
Трэш

S>Тот же COM out server тоже треш?

Это не трэш, это разложившийся труп

S> И кстати сколько выдает веб апи вызовов в секунду?

Посчитайте, возтмите тот же пример веб сервера на Pipelines и замеряйте.

S> Еще раз это замена AppDomain и Remotig. Они то надеюсь не треш?

Какая нафиг замена, очнитесь О чём вы вообще.
AppDomain предназначены для изоляции кода и возможности по разному настраивать безопастность, для того что бы иметь возможность выгружать сборку, IPC и ремоутинг тут только для обеспечения этих возможностей. Какой смысл в вашем IPC без реальных фич App Domain
Народная мудрось
всем все никому ничего(с).
Re[5]: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 21.02.17 11:15
Оценка:
Здравствуйте, Tom, Вы писали:

S>> А в чем треш? То есть RPC(Remoting),WCF это не треш?

Tom>Трэш

S>>Тот же COM out server тоже треш?

Tom>Это не трэш, это разложившийся труп

Угу а веб сервера это тот же труп только по другим протоколам.

S>> И кстати сколько выдает веб апи вызовов в секунду?

Tom>Посчитайте, возтмите тот же пример веб сервера на Pipelines и замеряйте.
Ну ты же говоришь, что это медленно, значит у тебя есть замеры?
Ну дык подскажи как для .Net Core Pipelines использовать. Буду благодарен.


S>> Еще раз это замена AppDomain и Remotig. Они то надеюсь не треш?

Tom>Какая нафиг замена, очнитесь О чём вы вообще.
Tom>AppDomain предназначены для изоляции кода и возможности по разному настраивать безопастность, для того что бы иметь возможность выгружать сборку, IPC и ремоутинг тут только для обеспечения этих возможностей. Какой смысл в вашем IPC без реальных фич App Domain

А какие фичи App Domain
Можно запустить процесс, передать в параметрах номер порта, настроить безопасность. В чем отличие?
и солнце б утром не вставало, когда бы не было меня
Re[5]: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 21.02.17 11:18
Оценка:
Здравствуйте, Tom, Вы писали:

S>> А в чем треш? То есть RPC(Remoting),WCF это не треш?

Tom>Трэш

Ясно и приложения должны обмениваться исключительно через HTTP сервисы и SignalR?
http://rsdn.org/forum/dotnet.web/6704296
Автор: alex1010
Дата: 21.02.17
и солнце б утром не вставало, когда бы не было меня
Re[6]: .Net Core, AppDomain, RPC свой велосипед
От: Tom Россия http://www.RSDN.ru
Дата: 21.02.17 11:30
Оценка:
S>Ясно и приложения должны обмениваться исключительно через HTTP сервисы и SignalR?
Причём тут SignalR вообще

Если вас ваше решение устраивает оно для вас белое пушистое и быстрое то пусть так и будет.
Народная мудрось
всем все никому ничего(с).
Re[7]: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 21.02.17 11:42
Оценка:
Здравствуйте, Tom, Вы писали:

S>>Ясно и приложения должны обмениваться исключительно через HTTP сервисы и SignalR?

Tom>Причём тут SignalR вообще
А как ты события передавать будешь?

Tom>Если вас ваше решение устраивает оно для вас белое пушистое и быстрое то пусть так и будет.

Так я хочу получить советы. Как сделать так, что бы это устраивало не только меня одного.
и солнце б утром не вставало, когда бы не было меня
Re[6]: .Net Core, AppDomain, RPC свой велосипед
От: Tom Россия http://www.RSDN.ru
Дата: 21.02.17 11:43
Оценка:
Tom>>Посчитайте, возтмите тот же пример веб сервера на Pipelines и замеряйте.
S>Ну ты же говоришь, что это медленно, значит у тебя есть замеры?
Посмотри тесты techempower, даже код который в базу лезет работает на 2 порядка быстрее.
Не говоря о plaintext

S> Ну дык подскажи как для .Net Core Pipelines использовать. Буду благодарен.

https://github.com/davidfowl/PipelinesSample

S>Можно запустить процесс, передать в параметрах номер порта, настроить безопасность. В чем отличие?

Во всём, глупая дискуссия.

ЗЫ: В упор не понимаю что и зачем ты делаешь. Сделать быстрый IO framework у тебя не получится, повторить функционал AppDomain тем более, тогда вопрос что вообще ты хочешь добиться.

ЗЫЫЫ: Если надо просто вызывать удалённый процесс — посмотри на grpc
Народная мудрось
всем все никому ничего(с).
Re[7]: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 21.02.17 12:18
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>>>Посчитайте, возтмите тот же пример веб сервера на Pipelines и замеряйте.

S>>Ну ты же говоришь, что это медленно, значит у тебя есть замеры?
Tom>Посмотри тесты techempower, даже код который в базу лезет работает на 2 порядка быстрее.
Tom>Не говоря о plaintext

S>> Ну дык подскажи как для .Net Core Pipelines использовать. Буду благодарен.

Tom>https://github.com/davidfowl/PipelinesSample

Ок посмотрю. Спасибо. Сейчас сделаю на Tcp/Ip потом возьмусь за PipelinesSample


S>>Можно запустить процесс, передать в параметрах номер порта, настроить безопасность. В чем отличие?

Tom>Во всём, глупая дискуссия.

Tom>ЗЫ: В упор не понимаю что и зачем ты делаешь. Сделать быстрый IO framework у тебя не получится, повторить функционал AppDomain тем более, тогда вопрос что вообще ты хочешь добиться.


Ну раз ты говоришь о том что пайпы на два порядка выше, то есть 200к вызовов в секунду, то это оочень быстрый Фреймворк.

Tom>ЗЫЫЫ: Если надо просто вызывать удалённый процесс — посмотри на grpc


Спасибо посмотрю.
и солнце б утром не вставало, когда бы не было меня
Re[8]: .Net Core, AppDomain, RPC свой велосипед
От: Tom Россия http://www.RSDN.ru
Дата: 21.02.17 12:32
Оценка:
S> Ок посмотрю. Спасибо. Сейчас сделаю на Tcp/Ip потом возьмусь за PipelinesSample
Я бы grpc в первую очередь смотрел
Народная мудрось
всем все никому ничего(с).
Re[9]: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 21.02.17 12:53
Оценка:
Здравствуйте, Tom, Вы писали:

S>> Ок посмотрю. Спасибо. Сейчас сделаю на Tcp/Ip потом возьмусь за PipelinesSample

Tom>Я бы grpc в первую очередь смотрел

У меня уже сделан через рефлексию вызов удаленных методов аналогичных C#.
То есть поддержка методов с params, с дефолтными параметрами, вызов дженерик методов итд.
То есть ты работаешь с удаленным объектом как со своим.
То есть, можно вызывать методы асинхронно
 var wrap = Client.AutoWrapClient.GetProxy("127.0.0.1", 6891); // Получили удаленный объект



 static async Task<object> GetAsyncResult(dynamic wrap)
    {

        object resTask = await wrap.async.ЧтотоТам(3);

       
        return resTask;
    }


Можно создавать объекты из сборки в каталоге сервера

var Тестовый = wrap.Тип("TestDllForCoreClr.Тестовый", "TestDll");// TestDll в каталоге сервера
        var TO = wrap.New(Тестовый,"Свойство из Конструктора");
        Console.WriteLine("Свойство Объекта " + TO.СвойствоОбъекта);
        TO.СвойствоОбъекта = "Свойство Новое";
        Console.WriteLine("Свойство Объекта " + TO.СвойствоОбъекта);

        var EO = TO.ПолучитьExpandoObject();
        Console.WriteLine("Свойство ExpandoObject Имя "+EO.Имя);
        Console.WriteLine("Свойство ExpandoObject Число "+EO.Число);


То есть код сервера можно не менять, только подсовывать нужные DLL, и создавать из них нужные объекты или вызывать статические методы.
Подключаться к событиям.
Это очень схоже с AppDamain

Можно подключаться к событиям по аналогии с
CEF, Angular 2 использование событий классов .Net Core

То есть можно использовать любой тип и вызывать его методы удаленно, подписываться на события.


У меня уже есть велосипед.
Я просто хочу довести до ума. Может кому и пригодится.
и солнце б утром не вставало, когда бы не было меня
Отредактировано 21.02.2017 13:26 Serginio1 . Предыдущая версия . Еще …
Отредактировано 21.02.2017 13:04 Serginio1 . Предыдущая версия .
Отредактировано 21.02.2017 13:02 Serginio1 . Предыдущая версия .
Re[5]: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 21.02.17 17:00
Оценка:
Здравствуйте, Tom, Вы писали:

S>> А в чем треш? То есть RPC(Remoting),WCF это не треш?

Tom>Трэш

S>>Тот же COM out server тоже треш?

Tom>Это не трэш, это разложившийся труп
Которым пользуется куча 1С и иже с ними.
При этом при переходе на 64 разрядную платформу, люди стали возвращаться обратно, так как in process повально 32 разрядные.
WCF я и сейчас пользуюсь с named pipes binding . Но в .Net Core нет, и при этом мою приблуду проще использовать.
Нужна любая сборка.

S>> И кстати сколько выдает веб апи вызовов в секунду?

Tom>Посчитайте, возтмите тот же пример веб сервера на Pipelines и замеряйте.

Вот появятся named pipes в .Net Core на уровне сокетов обязательно проверю.

S>> Еще раз это замена AppDomain и Remotig. Они то надеюсь не треш?

Tom>Какая нафиг замена, очнитесь О чём вы вообще.
Tom>AppDomain предназначены для изоляции кода и возможности по разному настраивать безопастность, для того что бы иметь возможность выгружать сборку, IPC и ремоутинг тут только для обеспечения этих возможностей. Какой смысл в вашем IPC без реальных фич App Domain

Все фичи App Domain есть. Можно управлять и секьюрностью и выгружать и создавать любой объект и вызывать его.
Какие еще нужны фичи?

Кстати Analog System.Security.Permissions in .NET Core


Code Access Security isn't and won't be available in .Net Core. Since all code is effectively running under full trust, it should be enough to remove those attributes.

If you actually want to restrict some code, the recommandation is:


Use operating system provided security boundaries, such as user accounts for running processes with the least set of privileges.

и солнце б утром не вставало, когда бы не было меня
Отредактировано 21.02.2017 17:09 Serginio1 . Предыдущая версия .
Re: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 22.02.17 16:16
Оценка:
Здравствуйте, Serginio1, Вы писали:
К сожалению C# не поддерживает вызов new для TryCreateInstance DinamicObject

Сейчас объект создается так

 var Тестовый = wrap.Тип("TestDllForCoreClr.Тестовый", "TestDll");
// На основании типа создадим объект
  var TO = wrap.New(Тестовый,"Свойство из Конструктора");


То есть мы не можем вызвать используя DinamicObject и TryCreateInstance

var TO = new Тестовый("Свойство из Конструктора");


Но можно и так

var TO = Тестовый.new("Свойство из Конструктора");


Еще один вариант это использовать

TryInvoke(): вызов объекта в качестве делегата

var TO = Тестовый($$,"Свойство из Конструктора");


где $$ константная строка для сравнения Object.ReferenceEquals
и солнце б утром не вставало, когда бы не было меня
Re: .Net Core, AppDomain, RPC свой велосипед
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 28.02.17 09:38
Оценка:
Здравствуйте, Serginio1, Вы писали:

Я прекрасно понимаю, что это никому не нужно. Но нужно доделать.
Сил вложено немало. В итоге получилось поделие даже не хуже WCF.
А по мне даже и лучше. Больше возможностей. И при этом можне не писать серверный код.
Очень близко к AppDomain, только все объекты являются MarshalByRefObject.

Поэтому прошу совета помочь оформить и покритиковать.

Что сейчас есть.
Можно подключиться к существующему серверу или запустить процесс по известному пути

if (LoadLocalServer)
        {
            //   connector = ClientRPC.TCPClientConnector.LoadAndConnectToLocalServer(GetParentDir(dir, 4) + $@"\Server\Server\bin\Release\netcoreapp1.1\Server.dll");
            connector = ClientRPC.TCPClientConnector.LoadAndConnectToLocalServer(GetParentDir(dir, 4) + $@"\Server\Server\bin\Debug\netcoreapp1.1\Server.dll");
        }
        else
        {
            connector = new ClientRPC.TCPClientConnector("127.0.0.1", port);
            // Нужен для асинхронных методов и Событий
            // Если их нет то и смысла слушать порт нет
            port = ClientRPC.TCPClientConnector.GetAvailablePort(6892);
            connector.Open(port, 2);

        }



После подключения можно получить типы и создавать объекты из сборок находящиеся в папке сервера и в паках CoreClr

            CoreClrDir = GetDirName(typeof(string));
            NetObjectToNativeDir = GetDirName(typeof(AutoWrap));



Поддержка статических и объектных методов, Дженерик методов с выводом типа, с дженерик аргуметами, индесаторов, итераторов
Поддержка асинхронных методов и событий. Поддержка ref и out параметров
Например

static async Task<object> GetGenericAsyncResult(dynamic TO)
    {
                 //public async Task<V> GenericMethodAsync<K, V>(K param, string param4 = "Test")
        object resTask = await TO.async.GenericMethodAsync(new object[] { "System.Int32", "System.String" }, 44);
        return resTask;
    }

static void TestGenericMethods(ClientRPC.TCPClientConnector connector)
    {


        Dictionary<int, string> ClientDict = new Dictionary<int, string>()
        {
            [1] = "Один",
            [2] = "Второй2",
            [3] = "Один3"
        };

        var @Dictionary2 = wrap.GetType("System.Collections.Generic.Dictionary`2", "System.Collections");
        var @DictionaryIntString = wrap.GetGenericType(@Dictionary2, "System.Int32", "System.String");

        // Скопируем словарь на сервер
        // Закомментированы различные варианты
        // var dict = connector.CoryTo(@DictionaryIntString, ClientDict);
        // var dict = connector.CoryTo("System.Collections.Generic.Dictionary`2[System.Int32, System.String]", ClientDict);

        // Скопируем словарь на сервер
        var dict = connector.CoryTo(ClientDict);

        Console.WriteLine(wrap.toString(dict));
        Console.WriteLine(dict[2]);

      // Получим тип из сборки TestDll
        var @TestClass = wrap.GetType("TestDllForCoreClr.TestClass", "TestDll");


       // Создадим объект на сервере используя метод _new
        var TO = @TestClass._new("Property  from Constructor");

        // Test асинхронного вызова дженерик метода

        var resGM = GetGenericAsyncResult(TO).Result;
        Console.WriteLine("Вызов дженерик метода с аргументами типов async " + resGM);


        // Вызовем дженерик метод с автовыводом типа
        // public T GenericMethod<V, T>(V param1, T param2, V param3)
        resGM = TO.GenericMethod(dict, 99, "Hello");
        Console.WriteLine("Вызов дженерик метода с выводом типа " + resGM);




        // Test Generic Method с параметрами по умолчанию 
        //public string GenericMethodWithDefaulParam<K, V>(Dictionary<K, V> param1, K param2, int param3 = 4, string param4 = "Test")
        var @Int32 = wrap.GetType("System.Int32");
        resGM = TO.GenericMethodWithDefaulParam(dict, 99);
        Console.WriteLine("Вызов дженерик метода с автовыводом  типов " + resGM);

        resGM = TO.GenericMethodWithDefaulParam(pp(@Int32, "System.String"), dict, 99);
        Console.WriteLine("Вызов дженерик метода с аргументами типов " + resGM);



        // Test Generic Method с параметрами массивом
        // public string GenericMethodWithParams<K, V>(Dictionary<K, V> param1, K param2, params string[] args)

        resGM = TO.GenericMethodWithParams(dict, 99, "First", "Second");
        Console.WriteLine("Вызов дженерик метода с автовыводом  типов " + resGM);

        resGM = TO.GenericMethodWithParams(pp(@Int32, "System.String"), dict, 99, "First", "Second");
        Console.WriteLine("Вызов дженерик метода с аргументами типов " + resGM);


        // public V  GenericMethodWithRefParam<К,V >(К param, V param2, ref string param3)
        var OutParam = new ClientRPC.RefParam("TroLoLo");
        resGM = TO.GenericMethodWithRefParam(5, "GenericMethodWithRefParam", OutParam);
        Console.WriteLine($@"Вызов дженерик метода с автовыводом  типов Ref {resGM}  {OutParam.Value}");
        var GenericArgs = new object[] { "System.String", "System.String" };


        resGM = TO.GenericMethodWithRefParam(GenericArgs, null, "GenericMethodWithRefParam", OutParam);
        Console.WriteLine($@"Вызов дженерик метода с дженерик аргументами Ref {resGM}  {OutParam.Value}");

        // Test return null
        resGM = TO.GenericMethodWithRefParam(GenericArgs, null, null, OutParam);
        Console.WriteLine($@"Вызов дженерик метода с дженерик аргументами Ref {resGM}  {OutParam}");


    }



Напрямую сериализуются byte[],числа, строки,булево,Дата,char,Guid
Для AutoWrapClient передается индекс в хранилище

Но можно скопировать данные на сервер и получить ссылку

var dict = connector.CoryTo(ClientDict);


Внутри используеся Json сериализация

 // Сериализуем объект и отправим представление типа ввиде AssemblyQualifiedName
        public dynamic CoryTo(object obj)
        {
            string type = obj.GetType().AssemblyQualifiedName;
            var str = JsonConvert.SerializeObject(obj);
            return CoryTo(type, str);

        }


При этом мы можем получить и ссылку на byte[], так при обычном методе он сериализуется.

Но для этого нужно загрузить все используемы сборки.

static void TestSerializeObject(ClientRPC.TCPClientConnector connector)
    {
       // Получим на клиенте объект и скопируем его на сервер
        var obj = new TestDllForCoreClr.TestClass("Объект на стороне Клиента");

        dynamic test = null;
        try
        {
            test = connector.CoryTo(obj);

        }
        catch (Exception)
        {

            Console.WriteLine("Ошибка " + connector.LastError);
            var assembly = wrap.GetAssembly("TestDll");
            test = connector.CoryTo(obj);

        }
        Console.WriteLine(test.ObjectProperty);

    }


Поддержка индексаторов и итераторов.


 string[] sa = new string[] { "Нулевой", "Первый", "Второй", "Третий", "Четвертый" };
        var ServerSA = connector.ArrayCoryTo("System.String", sa);
        Console.WriteLine("ServerSA[2]  " + ServerSA[2]);
        ServerSA[2] = "Изменен Параметр по индексу 2";
        Console.WriteLine("ServerSA[2]  " + ServerSA[2]);

        foreach (string value in ServerSA)
            Console.WriteLine("Values  " + value);




 var Dictionary2 = wrap.GetType("System.Collections.Generic.Dictionary`2", "System.Collections");
        var DictionaryIntString = wrap.GetGenericType(Dictionary2, "System.Int32", "System.String");
        //var dict = wrap.New(DictionaryIS);

      
        Dictionary<int, string> ClientDict = new Dictionary<int, string>()
        {
            [1] = "Один",
            [2] = "Второй2",
            [3] = "Один3"
        };

        foreach (string value in ServerSA)
            Console.WriteLine("Values  " + value);


        Console.WriteLine("new  " + DictionaryIntString._new());

        // Можно просто connector.CoryTo(ClientDict);
        // Но бывает что тип только на сервере. На клиенте такого типа нет
        //Но можно использоварть ExpandoObject или JObject
        
        var dict = connector.CoryTo(DictionaryIntString, ClientDict);
        Console.WriteLine("dict[2]  " + dict[2]);
        dict[2] = "Два";
        Console.WriteLine("dict[2]  " + dict[2]);

        // используем класс ClientRPC.RefParam для получения измененного параметра.
        var OutParam = new ClientRPC.RefParam();
        if (dict.TryGetValue(2, OutParam))
        {

            Console.WriteLine("OutParam  " + OutParam.Value);
        }



Вобщем отличие от родного кода это в вызове асинхронного метода за счет добавления слова async

        object resTask = await TO.async.GenericMethodAsync(new object[] { "System.Int32", "System.String" }, 44);


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




// public V  GenericMethodWithRefParam<К,V >(К param, V param2, ref string param3)
        var OutParam = new ClientRPC.RefParam("TroLoLo");
        var GenericArgs = new object[] { "System.String", "System.String" };


        resGM = TO.GenericMethodWithRefParam(GenericArgs, null, "GenericMethodWithRefParam", OutParam);




Ну и подключение к эвентам



 static public void EventWithTwoParameter(dynamic value)
    {
        Console.WriteLine("EventWithTwoParameter" + wrap.toString(value));

        value(ClientRPC.AutoWrapClient.FlagDeleteObject);
    }

    // параметр value:System.String

    static public void EventWithOneParameter(dynamic value)
    {
        Console.WriteLine("EventWithOneParameter " + wrap.toString(value));
    }


    static public void EventWithOutParameter(dynamic value)
    {
        Console.WriteLine("EventWithOutParameter" + wrap.toString(value));
    }

 static void RunTestEvent(ClientRPC.TCPClientConnector connector)
    {
        var EventTest = wrap.GetType("TestDllForCoreClr.EventTest", "TestDll");
        // var test = wrap.New(EventTest);
        var test = EventTest._new();
        var wrapForEvents = connector.CreateWrapperForEvents(test);


        wrapForEvents.AddEventHandler("EventWithTwoParameter", new Action<dynamic>(EventWithTwoParameter));
        wrapForEvents.AddEventHandler("EventWithOneParameter", new Action<dynamic>(EventWithOneParameter));
        wrapForEvents.AddEventHandler("EventWithOutParameter", new Action<dynamic>(EventWithOutParameter));
        test.Run();
    }



Основное отличие от WCF это использование DynamicObjet. Но можно тестировать код напрямую, а затем
приспосабливать его к PPC
и солнце б утром не вставало, когда бы не было меня
Отредактировано 28.02.2017 10:19 Serginio1 . Предыдущая версия . Еще …
Отредактировано 28.02.2017 10:19 Serginio1 . Предыдущая версия .
Отредактировано 28.02.2017 10:17 Serginio1 . Предыдущая версия .
Отредактировано 28.02.2017 10:16 Serginio1 . Предыдущая версия .
Отредактировано 28.02.2017 10:13 Serginio1 . Предыдущая версия .
Отредактировано 28.02.2017 9:53 Serginio1 . Предыдущая версия .
Отредактировано 28.02.2017 9:51 Serginio1 . Предыдущая версия .
Отредактировано 28.02.2017 9:49 Serginio1 . Предыдущая версия .
Отредактировано 28.02.2017 9:47 Serginio1 . Предыдущая версия .
Re: .Net Core, AppDomain, RPC свой велосипед
От: hardcase Пират http://nemerle.org
Дата: 28.02.17 10:19
Оценка: +1
Здравствуйте, Serginio1, Вы писали:

S>Кто о чем, а вшивый о бане.


S> Сейчас в .Net Core нет AppDomain и RPC .


Я бы использовал Protobuf + как там принято в .NET Core сообщения передавать между процессами. Никакой рефлексии, магии аля MarshalByRefObject и граблей с маршаллингом того, что не предназначено для маршаллинга.
/* иЗвиНите зА неРовнЫй поЧерК */
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.