Информация об изменениях

Сообщение Re: .Net Core, AppDomain, RPC свой велосипед от 28.02.2017 9:38

Изменено 28.02.2017 9:47 Serginio1

Re: .Net Core, AppDomain, RPC свой велосипед
Здравствуйте, Serginio1, Вы писали:

Я прекрасно понимаю, что это никому не нужно. Но нужно доделать.
Сил вложено немало. В итоге получилось поделие даже не хуже WCF.
А по мне даже и лучше. Больше возможностей. И при этом можне не писать серверный код.
Очень близко к AppDomaintю Только все объекты являются 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)
    {

        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]);
        var @TestClass = wrap.GetType("TestDllForCoreClr.TestClass", "TestDll");


        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);

        }



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

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
Re: .Net Core, AppDomain, RPC свой велосипед
Здравствуйте, Serginio1, Вы писали:

Я прекрасно понимаю, что это никому не нужно. Но нужно доделать.
Сил вложено немало. В итоге получилось поделие даже не хуже WCF.
А по мне даже и лучше. Больше возможностей. И при этом можне не писать серверный код.
Очень близко к AppDomaintю Только все объекты являются 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)
    {

        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]);
        var @TestClass = wrap.GetType("TestDllForCoreClr.TestClass", "TestDll");


        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);

        }



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

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