Есть Com+ компонент, написанный на C#. В его проект добавлены refы на другие библиотеки.
Тесты (создается тестовый проект, создающий объект):
1) Объект не является COM+ компонентом — все работает на ура.
2) Объект является COM+ компонентом — регистрируется в папке Debug тестового проекта. Вызов AppDomain.CreateInstance(MyAsmStr,MyTypeStr) возвращает не то, что в первом тесте. А именно, объект MarshalByRefObject не может быть приведен к типу MyType. При создании всех AppDomain — ApplicationBase == DebugFolder тестового проекта.
3) Зарегистрированный компонент запускается при помощи Службы компонентов — вообще не может найти не один ref, т.к. запускается из %System%.
Вопросы:
1) почему поведение AppDomain.CreateInstaince различно в первом и втором случае?
2) как разрешить зависимости в третьем случае без помещения сборок в ГАК?
Здравствуйте, AThe, Вы писали:
AT>Есть Com+ компонент, написанный на C#. В его проект добавлены refы на другие библиотеки. AT>Тесты (создается тестовый проект, создающий объект): AT>1) Объект не является COM+ компонентом — все работает на ура. AT>2) Объект является COM+ компонентом — регистрируется в папке Debug тестового проекта. Вызов AppDomain.CreateInstance(MyAsmStr,MyTypeStr) возвращает не то, что в первом тесте. А именно, объект MarshalByRefObject не может быть приведен к типу MyType. При создании всех AppDomain — ApplicationBase == DebugFolder тестового проекта. AT>3) Зарегистрированный компонент запускается при помощи Службы компонентов — вообще не может найти не один ref, т.к. запускается из %System%.
AT>Вопросы: AT>1) почему поведение AppDomain.CreateInstaince различно в первом и втором случае? AT>2) как разрешить зависимости в третьем случае без помещения сборок в ГАК?
Давненько я этим не занимался, отвечаю по памяти.
1. У тебя в данном случае (по меньшей мере, если речь идет о com-приложении, а не библиотеке) и должен быть MarshalByRefObject. Приводиться он должен к интерфейсу (ты ведь определил интерфейс и назначил ему Guid, правда?).
2. В настройках COM+ приложения есть рабочая папка, которую можно задать.
Здравствуйте, mrozov, Вы писали:
M>Давненько я этим не занимался, отвечаю по памяти.
M>1. У тебя в данном случае (по меньшей мере, если речь идет о com-приложении, а не библиотеке) и должен быть MarshalByRefObject. Приводиться он должен к интерфейсу (ты ведь определил интерфейс и назначил ему Guid, правда?). M>2. В настройках COM+ приложения есть рабочая папка, которую можно задать.
Оказалось первая проблема — следствие второй. Вот тестовый пример.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace Reference
{
public class ReferenceClass
: MarshalByRefObject
{
public ReferenceClass()
{
}
private void Log(string message)
{
using (StreamWriter sw = new StreamWriter("c:\\ComPlusComponent.log", true))
sw.WriteLine(message);
}
public void Init()
{
Log("Init Called");
}
}
}
Тестовый проект.
using System;
using System.Collections.Generic;
using System.Text;
using ComPlusComponent;
namespace Test
{
class Program
{
static void Main(string[] args)
{
ComPlusComponentClass c = new ComPlusComponentClass();
}
}
}
Вот результаты.
Test1
Z:\Tries\TryComPlus\Test\bin\Debug\
Init Called
Test2
C:\WINDOWS\system32\
System.IO.FileNotFoundException
Could not load file or assembly 'file:///C:\WINDOWS\system32\Reference.dll' or one of its dependencies. Не удается найти указанный файл. Здесь вставляем путь к Com-dll в Службы компонентов->ComPlusComponent->Активизация->Корневая папка приложения
Test2
C:\WINDOWS\system32\
System.IO.FileNotFoundException
Could not load file or assembly 'file:///C:\WINDOWS\system32\Reference.dll' or one of its dependencies. Не удается найти указанный файл.
Test3
C:\WINDOWS\system32\
System.IO.FileNotFoundException
Could not load file or assembly 'file:///C:\WINDOWS\system32\Reference.dll' or one of its dependencies. Не удается найти указанный файл.
Test4
C:\WINDOWS\system32\
Z:\Tries\TryComPlus\Test\bin\Debug
System.MarshalByRefObject
System.InvalidCastException
Unable to cast transparent proxy to type 'Reference.ReferenceClass' Переписываем Reference.dll в System32
Test2
C:\WINDOWS\system32\
Init Called
Test3
C:\WINDOWS\system32\
Reference.ReferenceClass
Init Called
Test4
C:\WINDOWS\system32\
Z:\Tries\TryComPlus\Test\bin\Debug
Reference.ReferenceClass
Init Called
Здравствуйте, AThe, Вы писали:
AT>Здравствуйте, mrozov, Вы писали:
M>>Давненько я этим не занимался, отвечаю по памяти.
M>>1. У тебя в данном случае (по меньшей мере, если речь идет о com-приложении, а не библиотеке) и должен быть MarshalByRefObject. Приводиться он должен к интерфейсу (ты ведь определил интерфейс и назначил ему Guid, правда?). M>>2. В настройках COM+ приложения есть рабочая папка, которую можно задать.
AT>Оказалось первая проблема — следствие второй. Вот тестовый пример.
<skiped> AT>Где копать?
Обязательно выполнить пункт 1.
Без этого к com+ не подходить. Тут штука такая — на первый взгляд может показаться, что оно как бы работает. Но эта видимость, товарищи, только кажущаяся.
Здравствуйте, mrozov, Вы писали:
M>>>1. У тебя в данном случае (по меньшей мере, если речь идет о com-приложении, а не библиотеке) и должен быть MarshalByRefObject. Приводиться он должен к интерфейсу (ты ведь определил интерфейс и назначил ему Guid, правда?). M>>>2. В настройках COM+ приложения есть рабочая папка, которую можно задать.
AT>>Оказалось первая проблема — следствие второй. Вот тестовый пример. M><skiped> AT>>Где копать?
M>Обязательно выполнить пункт 1. M>Без этого к com+ не подходить. Тут штука такая — на первый взгляд может показаться, что оно как бы работает. Но эта видимость, товарищи, только кажущаяся.
С этим все в порядке. Просто в тестовом проекте это упущено. Все работало и было оттестировано. Потом в проект добавили новую функциональность — у COM-объекта появились зависимости от библиотек, не помещенных в ГАК и не находящихся в System32. Так что вопрос остался открытым.
Здравствуйте, AThe, Вы писали:
AT>С этим все в порядке. Просто в тестовом проекте это упущено. Все работало и было оттестировано. Потом в проект добавили новую функциональность — у COM-объекта появились зависимости от библиотек, не помещенных в ГАК и не находящихся в System32. Так что вопрос остался открытым.
Хм...
Проблема проявляется только при создании объекта в другом домене?
Я правильно понимаю — просто ReferenceClass виден и его можно создать, но вы реализуете систему плагинов.
Код в Test4 показывает, что с получением адреса подключаемой dll вы справляетесь успешно, но полученная сборка с точки зрения runtime отличается от той, с которой запущен проект?
Может, стоит под отладчиком зайти и посмотреть, что там происходит?
Здравствуйте, mrozov, Вы писали:
M>Хм... M>Проблема проявляется только при создании объекта в другом домене?
Оказалось, что нет. Был написан еще тест в котором просто выполняется:
ReferenceClass refer = new ReferenceClass();
refer.Init();
Говорит : Could not load file or assembly 'Reference, Version=1.0.0.0, Culture=neutral, PublicKeyToken=259e45bab0c62d86' or one of its dependencies. Не удается найти указанный файл.
M>Я правильно понимаю — просто ReferenceClass виден и его можно создать, но вы реализуете систему плагинов.
Получается, что не виден.
M>Код в Test4 показывает, что с получением адреса подключаемой dll вы справляетесь успешно, но полученная сборка с точки зрения runtime отличается от той, с которой запущен проект?
Если я правмльно понимаю, то происходит во что:
1) проект выполняет
ComPlusComponentClass c = new ComPlusComponentClass();
2) из директории System32 запускается dllhost, который создает outproc компонент.
3) в статическом конструкторе компонента создается домен, в котором создается объект класса ReferenceClass и возвращается в домен компонента, который не может найти сборку Reference для приведения типа, поэтому приводит объект к MarshalByRefObject.
M>Может, стоит под отладчиком зайти и посмотреть, что там происходит?
Подтверждается вышесказанное: компонент не видит сборку Reference.dll в рантайме.
У меня подобная схема после прописывания исполняемой директории в качестве корневой для процесса успешно работала. Скорее всего проблема в какой-нибудь мелочи в настройках.
Можно в GAC положить, наверное, в крайнем случае.
Удачи.
Здравствуйте, mrozov, Вы писали:
M>Здравствуйте, mrozov, Вы писали:
M>>Здравствуйте, AThe, Вы писали:
M>> M>>Ничем не могу помочь.
M>А хотя... с учетом результата теста №4, можно воспользоваться событием AppDomain.AssemblyResolve
Сделал по-другому. Выделил интерфейс IReferenceClass в отдельную сборку и поместил ее в ГАК. Помещение ReferenceDll в ГАК повлекло бы за собой помещение туда же всего проекта, что не очень хорошо. А так, вроде, все сработало. Еще раз спасибо за ваши ответы.