Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Реализация RPC


Автор: gpepsi 31.8.2012, 18:40
На машине существуют COM объекты,  которые реализуют некоторые интерфейсы.
С другой машины необходимо удаленно вызывать методы интерфейса.

Задача 1: уйти от COM объектов создав некую абстракцию.
Задача 2: сделать это максимально платформонезависимо.

В голову пришел простой способ реализации на основе JSON.
Передача данных по сети Tcp-клиентом (может быть механизм более высокого уровня).

Сначала попытался реализовать каждый метод.

Например:
Код

class IComObject1
{
    void method1();
    void method2();
    ...
    void methodN();
}
...
class IComObjectN
{
    void method1();
    void method2();
    ...
    void methodN();
}

class JsonCmds
{
    public static readonly METHOD_ICOMOBJECT1_METHOD1 = "IComObject1.method1";
    ...
    public static readonly METHOD_ICOMOBJECTN_METHODN = "IComObjectN.methodM";
}


Соответственно, получив JSON запрос я просто проверяю метод и вызываю нужный.
В рельтате получается офигенный if/else if т.к. методов много.

Также возникает проблема с передвчей аргументов. Каждый метод должен знать какие аргументы каких типов 
должны быть переданы.

Хотелось бы это унифицировать. Например, по типу класса найти нужный объект и вызвать метод по строковому имени.
Только типы класса и методы передаются как строки.

Можно ли это реализовать ?

Автор: Cheloveck 1.9.2012, 02:24
Может не нужно изобретать велосипед и воспользоваться http://msdn.microsoft.com/en-us/library/dd456779.aspx?

Автор: gpepsi 1.9.2012, 08:15
Цитата(Cheloveck @  1.9.2012,  02:24 Найти цитируемый пост)
Может не нужно изобретать велосипед и воспользоваться WCF? 

я же говорил - платформонезависимо.

P.S. тут искал и нашел всякие Type и GetMethod. Может как это прикрутить можно ?

Автор: diadiavova 1.9.2012, 10:04
Цитата(gpepsi @  1.9.2012,  09:15 Найти цитируемый пост)
я же говорил - платформонезависимо.

Хочешь сказать, что машина, на которой "существуют" COM-объекты не под виндой работает? smile Если кроссплатформенность требуется для удаленной машины, то с WCF никаких проблем не возникнет, поскольку данными машины будут обмениваться с помощью XML или JSON, да и WSDL описание сервиса тоже будет сгенерировано.
Цитата(gpepsi @  1.9.2012,  09:15 Найти цитируемый пост)
P.S. тут искал и нашел всякие Type и GetMethod. Может как это прикрутить можно ? 

Можно, правда дать подробные инструкции трудно, поскольку не совсем понятно, как ты работаешь с COM. Обычно сборка взаимодействия генерится сама при добавлении ссылки на библиотеку или с помощью утилиты tlbimp. Но если ты все сам делаешь, то конкретно для твоего случая порядок действий примерно таков:
В пространстве System.Reflection находится почти все, что понадобится. Assembly - этот класс содержит ряд статических методов, с помощью которых можно получить ссылку на сборку. Далее вызываешь у нее метод CreateInstance для получения экземпляра, для этого правда придется передать ему полное имя класса, но если они все в одном пространстве имен - это не проблема. Получив экземпляр для получения Type вызови у него GetType, далее GetMethod( ему надо передать имя и опять-таки строкой, как тебе и надо), ну а уже у метода Invoke

Автор: Cheloveck 1.9.2012, 15:11
Цитата(gpepsi @  1.9.2012,  09:15 Найти цитируемый пост)
я же говорил - платформонезависимо.


Цитата(diadiavova @  1.9.2012,  11:04 Найти цитируемый пост)
с WCF никаких проблем не возникнет, поскольку данными машины будут обмениваться с помощью XML или JSON, да и WSDL 

Можно использовать http://msdn.microsoft.com/en-us/library/cc668792.aspx и экспозить http://www.odata.org/, клиенты для которой есть http://www.odata.org/libraries.

Автор: gpepsi 2.9.2012, 08:21
Цитата(diadiavova @  1.9.2012,  10:04 Найти цитируемый пост)
Хочешь сказать, что машина, на которой "существуют" COM-объекты не под виндой работает?

до этом машины пофигу. Вопрос к машине управления (хоть наладонник, хоть PC,...)

Цитата(diadiavova @  1.9.2012,  10:04 Найти цитируемый пост)
Получив экземпляр для получения Type вызови у него GetType

Я создаю экземпляры COM. Получается, что мне нужно после создания держать карту
Map<String, Object>, чтоб можно было найти по имени типа нужный COM ?

Цитата(diadiavova @  1.9.2012,  10:04 Найти цитируемый пост)
алее GetMethod( ему надо передать имя и опять-таки строкой, как тебе и надо),

это понятно

Цитата(diadiavova @  1.9.2012,  10:04 Найти цитируемый пост)
 ну а уже у метода Invoke

вот тут тоже проблема. Число и тип аргументов различны. Как выэывать методы через Invoke ?
Ведь сигнатуру метода знает только вызывающий код (на управляющей машине). А код на стороне COM хотелось бы вызывать универсально.

Может ли Invoke принимать массив аргументов типа object и сам понимать сколько ему аргументов нужно и какого типа ?


Автор: diadiavova 2.9.2012, 08:36
Цитата(gpepsi @  2.9.2012,  09:21 Найти цитируемый пост)
Я создаю экземпляры COM. Получается, что мне нужно после создания держать карту
Map<String, Object>, чтоб можно было найти по имени типа нужный COM ?

Давай начнем с того, как ты их создаешь и как вообще работаешь с ком. Обычно для этого генерируется сборка взаимодействия, в которой все типы являются CLR-типами и никакой проблемы рефлексии в этом плане быть не должно. Если ты делаешь это иначе, то опиши как и почему. Поначалу ты вообще написал, что создал собственные оболочки для ком-типов(насколько я понял).
Цитата(gpepsi @  2.9.2012,  09:21 Найти цитируемый пост)
Может ли Invoke принимать массив аргументов типа object и сам понимать сколько ему аргументов нужно и какого типа ?

Инвоук не может, но методинфо(объект, у которого ты вызываешь инвоук) содержит сведения о параметрах.

Автор: gpepsi 2.9.2012, 09:13
Цитата(diadiavova @  2.9.2012,  08:36 Найти цитируемый пост)
Давай начнем с того, как ты их создаешь и как вообще работаешь с ком.

я создаю их через Microsoft.VisualBasic.Interaction.CreateObject
получаю интерфейс, и работаю с ним вызывая методы.


Цитата(diadiavova @  2.9.2012,  08:36 Найти цитируемый пост)
Инвоук не может, но методинфо(объект, у которого ты вызываешь инвоук) содержит сведения о параметрах. 

то есть ему можно передать массив аргументов ?

Автор: diadiavova 2.9.2012, 09:19
Цитата(gpepsi @  2.9.2012,  10:13 Найти цитируемый пост)
я создаю их через Microsoft.VisualBasic.Interaction.CreateObject
получаю интерфейс, и работаю с ним вызывая методы.

Ну вот в этом причина того, что ты не можешь получить сведений о типе. Добавь ссылку на соответствующую библиотеку и все значительно упростится.
Цитата(gpepsi @  2.9.2012,  10:13 Найти цитируемый пост)
то есть ему можно передать массив аргументов ? 

Ну, а что по-твоему представляет из себя второй параметр метода?
http://msdn.microsoft.com/ru-ru/library/a89hcwhh%28VS.100%29.aspx

Автор: gpepsi 2.9.2012, 10:44
Цитата(diadiavova @  2.9.2012,  09:19 Найти цитируемый пост)
Добавь ссылку на соответствующую библиотеку и все значительно упростится.

а что мне это даст ?

Автор: diadiavova 2.9.2012, 11:09
Цитата(gpepsi @  2.9.2012,  11:44 Найти цитируемый пост)
а что мне это даст ? 

Как минимум сведения о типах. И вот это
Цитата(gpepsi @  2.9.2012,  09:21 Найти цитируемый пост)
Получается, что мне нужно после создания держать карту
Map<String, Object>, чтоб можно было найти по имени типа нужный COM ?

тебе уже не понадобится.

Автор: gpepsi 2.9.2012, 12:43
Цитата(diadiavova @  2.9.2012,  11:09 Найти цитируемый пост)
тебе уже не понадобится. 


diadiavova, я слабоват в C#. Можно подробнее пояснить или примерчик для наглядности

Автор: diadiavova 2.9.2012, 14:56
Цитата(gpepsi @  2.9.2012,  13:43 Найти цитируемый пост)
 Можно подробнее пояснить 

Добавляешь в проект ссылку на библиотеку, в которой определены нужные ком-классы и все интерфейсы будут доступны как обычные нет типы. Дальше сможешь с помощью рефлексии получить тип по имени в том числе. Добавь ссылку и сам все увидишь.

Автор: gpepsi 2.9.2012, 15:28
Цитата(diadiavova @  2.9.2012,  14:56 Найти цитируемый пост)
Дальше сможешь с помощью рефлексии получить тип по имени в том числе.

имеется ввиду создать экземпляр по имени ?

Автор: diadiavova 2.9.2012, 17:04
Цитата(gpepsi @  2.9.2012,  16:28 Найти цитируемый пост)
имеется ввиду создать экземпляр по имени ?

Аааааааа. Не знаю с какими ком-типами ты работаешь. Для примера возьмем библиотеку Scripting Runtime. (находится по адресу C:\Windows\System32\scrrun.dll). Допустим мне пришло имя FileSystemObject и надо создать экземпляр этого типа. Для начала нам понадобится ссылка на сборку, в которой определены типы. Если ты пишешь под 4-ый фреймворк, то по умолчанию типы внедряются в твою сборку, а это нам не надо. Для того, чтобы сборка взаимодействия создавалась отдельно, в обозревателе решений открой ветку "Ссылки", найди там свою ком-библиотеку(в моем случае она называется Scripting), выдели ее и перейди в окно свойств(или через контекстное меню), там увидишь свойства сборки, тебе надо свойству "Внедрить типы взаимодействия" присвоить False.

В коде сначала надо получить ссылку на сборку взаимодействия, в которой определены нужные типы. Проще всего это сделать, используя какой-нибудь тип, определенный в этой сборке. Я использовал все тот же FileSystemObject, хотя можно было и любой другой, они все имеют ссылку на свою сборку
Код

Assembly asm = typeof(Scripting.FileSystemObject).Assembly;
Теперь имея сборку можно получить объект
Код

object obj = Activator.CreateComInstanceFrom(asm.Location, "Scripting.FileSystemObjectClass").Unwrap();
Как видишь, от сборки нам понадобился только путь к файлу, а к полному имени типа добавился суффикс "Class". Дальше с этим объектом можно работать.

Добавлено через 35 секунд
Не забудь импортировать 
Код

using System.Reflection;

Автор: gpepsi 2.9.2012, 18:15
diadiavova, спасибо. буду разбираться.
З.Ы. Только еще вопрос - если экземпляр создан, то вызов
Код

object obj = Activator.CreateComInstanceFrom(asm.Location, "Scripting.FileSystemObjectClass").Unwrap();

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

Автор: diadiavova 2.9.2012, 19:05
Цитата(gpepsi @  2.9.2012,  19:15 Найти цитируемый пост)
создаст еще один экземпляр или получу указатель на созданный ранее ? Мне нужно второе. 

Еще один экземпляр. Если тебе нужна переменная, ссылающаяся на тот же объект - просто присвой ей эту ссылку
Код

obj2 = obj;
Объекты ссылочных типов не дублируются при присвоении.

Автор: gpepsi 3.9.2012, 12:08
что-то не получается создать объект.
Добавил ссылку на объект.
Смотрю Interop.MyWHostLib
  - WHostObj - интерфейс
  - WHostObjClass - класс
  - IWHostObj - интерфейс

Получаю сборку
Код

Assembly asm = typeof(MyWHostLib.WHostObj).Assembly;

успешно.

Создаю объект
Код

object obj = Activator.CreateComInstanceFrom(asm.Location, "MyWHostLib.WHostObjClass").Unwrap();


ошибка - не можетпривести тип объекта "System.__ComObject" к типу "MyWHostLib.WHostObjClass";

Добавлено через 6 минут и 14 секунд
P.S. Забыл скачать, что объект создавался так
Код

(IWHostObj)Interaction.CreateObject("MyWHostLib.WHostObj", address);


то естьб он принимал агрументом адрес и кастовался к интерфейсу

Автор: diadiavova 3.9.2012, 20:57
Цитата(gpepsi @  3.9.2012,  13:08 Найти цитируемый пост)
ошибка - не можетпривести тип объекта "System.__ComObject" к типу "MyWHostLib.WHostObjClass";

В том коде, что ты привел, приведения типов нет, так что ошибка как раз видимо возникает там, где ты используешь CreateObject. Для чего ты его используешь - непонятно. Креэйтобжект делает то же, что и активатор, только по программному идентификатору, а не по имени класса, да и без сборки взаимодействия. Так что уж надо использовать либо то, либо другое. Для чего ты пытаешься приведение типов выполнить - тоже непонятно, тип тебе заранее известен не будет, именно поэтому приходится работать через рефлексию, так что работай с типом объект.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)