Как пройти ссылки как параметры метода по адресу appdomains?

StackOverflow https://stackoverflow.com/questions/2932370

Вопрос

Я пытался получить следующий код для работы (все определено в той же сборке):

namespace SomeApp{

public class A : MarshalByRefObject
{
   public byte[] GetSomeData() { // }
}

public class B : MarshalByRefObject
{
   private A remoteObj;

   public void SetA(A remoteObj)
   {
      this.remoteObj = remoteObj;
   }
}

public class C
{
   A someA = new A();
   public void Init()
   {
       AppDomain domain = AppDomain.CreateDomain("ChildDomain");
       string currentAssemblyPath = Assembly.GetExecutingAssembly().Location;
       B remoteB = domain.domain.CreateInstanceFromAndUnwrap(currentAssemblyPath,"SomeApp.B") as B;
       remoteB.SetA(someA); // this throws an ArgumentException "Object type cannot be converted to target type."
   }
}

}

То, что я пытаюсь сделать, это передавать ссылку на экземпляр «A», созданный в первом AppDomain к домену домена, и иметь дочерний домен, выполнил метод в первом домене. В какой-то момент в «B» код я собираюсь назвать «REDUREOBJ.Getsomedata ()». Это должно быть сделано, потому что метод «байт []» из «Getsomedata» должен быть «рассчитанным» на первом приложении. Что мне делать, чтобы избежать исключения, или что я могу сделать для достижения того же результата?

Это было полезно?

Решение

Я могу дублировать проблему, и, похоже, связано с testdriven.net и / или xunit.net. Если я запускаю C.init () в качестве метода теста, я получаю то же сообщение об ошибке. Однако, если я запускаю C.init () из приложения консоли, я не получаю исключение.

Вы видите то же самое, запустите C.Init () из модульного теста?

Редактировать: Я также могу продублировать проблему с помощью NUNIT и TESTDRIVEN.NET. Я также могу продублировать ошибку, используя NUNIT Runner вместо TestDriven.net. Таким образом, проблема, кажется, связана с выполнением этого кода через систему тестирования, хотя я не уверен, почему.

Другие советы

Фактическая корневая причина была вашей DLL загружена из разных мест в двух разных доменах приложений. Это приводит к тому, что они думают, что они разные сборки, которые, конечно, означает, что типы различны (даже если они имеют одинаковое имя класса, пространство и т. Д.).

Испытание по причинам, причина, когда проходил тест Джеффа, когда выполнял блок тестовой базы, заключается в том, что структура тестирования единиц, как правило, создает Appdomains с помощью ShadowCopy, установленной на «True». Но ваш вручную создан Appdomain по умолчанию для ShadowCopy = «false». Это приведет к загрузке DLL из разных мест, которые приводят к приятным «Тип объекта», нельзя преобразовать в тип цели ». ошибка.

ОБНОВЛЕНИЕ: После дальнейшего тестирования, кажется, спускается к ApplicationBase, отличающейся между двумя appdomains. Если они совпадают, то приведенный выше сценарий работает. Если они отличаются, это не так, даже если я подтвердил, что DLL загружается как в Appdomains, из того же каталога, используя WINDBG) Кроме того, если я включаю ShadowCopy = «True» в обоих моих Appodomains, то это не удается С другим сообщением: «System.invalidcastexception: объект должен реализовать iconblible».

UPDATE2: дальнейшее чтение ведет меня верить, что это связано с Загрузить контексты. Отказ Когда вы используете один из методов «из» (AssembloadFrom или appdomain.createinstancefromandunwrap), если сборка найден в одном из нормальных путей нагрузки (ApplicationBase или один из путей зондирования), то он загружен в по умолчанию. Контекст нагрузки. Если сборка там не найдена, то она загружена в нагрузку - от контекста. Таким образом, когда оба appodomains имеют соответствующую прикладной панель, то даже хотя мы используем метод «из», они оба загружаются в контекст нагрузки на по умолчанию соответствующую настройку. Но когда ApplicationBase различны, то один appdomain будет иметь сборку в его контексте нагрузки по умолчанию, а другой имеет сборку в ее нагрузке.

Это комментарий @russellmcclure, но, как это сложно для комментариев, я публикую это как ответ:

Я внутри приложения ASP.NET и отключение тени-копирования (которая также решила проблему) на самом деле не является опцией, но я нашел следующее решение:

AppDomainSetup adSetup = new AppDomainSetup();
if (AppDomain.CurrentDomain.SetupInformation.ShadowCopyFiles == "true")
{
    var shadowCopyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (shadowCopyDir.Contains("assembly"))
        shadowCopyDir = shadowCopyDir.Substring(0, shadowCopyDir.LastIndexOf("assembly"));

    var privatePaths = new List<string>();
    foreach (var dll in Directory.GetFiles(AppDomain.CurrentDomain.SetupInformation.PrivateBinPath, "*.dll"))
    {
        var shadowPath = Directory.GetFiles(shadowCopyDir, Path.GetFileName(dll), SearchOption.AllDirectories).FirstOrDefault();
        if (!String.IsNullOrWhiteSpace(shadowPath))
            privatePaths.Add(Path.GetDirectoryName(shadowPath));
    }

    adSetup.ApplicationBase = shadowCopyDir;
    adSetup.PrivateBinPath = String.Join(";", privatePaths);
}
else
{
    adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
    adSetup.PrivateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath;
}

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

Если кто-то имеет лучший способ сделать это, пожалуйста, скажите мне.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top