2017-01-02 5 views
0

Моя цель: Я пишу vsix (расширение Visual Studio), где я хочу скомпилировать проект, а затем загрузить полученный DLL и проверить его через отражение. Из-за того, как написан код, я не могу использовать ReflectionOnlyLoad(). Если я просто делаю Assembly.Load, тогда файл заблокирован, пока пользователь не перезапустит всю среду IDE.Assembly.LoadFrom() или Assembly.Load(), способный удалить файл

Я пытаюсь настроить отдельный AppDomain на основе образцов, которые я нашел в Интернете.

Суть его является: 1. Я создал класс Proxy, который МАРШАЛ данные по AppDomain случаях:

internal class AppDomainProxy : MarshalByRefObject 
    { 
     public Assembly GetAssembly(string assemblyPath) 
     { 
      return Assembly.LoadFile(assemblyPath); 
     } 
} 

Я затем создать экземпляр этого:

var domaininfo = new AppDomainSetup { ApplicationBase = System.Environment.CurrentDirectory, ShadowCopyDirectories = "true", ShadowCopyFiles = "true", LoaderOptimization = LoaderOptimization.MultiDomainHost }; 

      var adevidence = System.AppDomain.CurrentDomain.Evidence; 
      var domain = System.AppDomain.CreateDomain("reflection", adevidence, domaininfo); 

      var proxyType = new AppDomainProxy().GetType(); 

      var proxyInstance = (AppDomainProxy)domain.CreateInstanceFromAndUnwrap(proxyType.Assembly.Location, proxyType.FullName); 

      var loadedAssembly = (proxyInstance as AppDomainProxy).GetAssembly(this._assemblyLocation); 

Это не удалось передать мой прозрачный прокси для моего AppDomainProxy. Чтобы обойти это, можно легко поставить сборочный распознаватель следующим образом:

  this.domain.AssemblyResolve += CurrentDomainOnAssemblyResolve; 

private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args) 
     { 
      var loadedAssemblies = System.AppDomain.CurrentDomain.GetAssemblies(); 

      foreach (var assembly in loadedAssemblies) 
      { 
       if (assembly.FullName == args.Name) 
       { 
        return assembly; 
       } 
      } 

      return null; 
     } 

Это прекрасно работает, мой прокси отливают. Однако, когда я вызываю свой метод, вызывается CurrentDomainOnAssemblyResolve, предлагая мне, что свойство Assembly не является сериализуемым и поэтому .net просто пытается загрузить сборку с исходной стороны, что приводит к той же проблеме, что и Assembly.Load. Это легко увидеть, потому что простые образцы Microsoft, такие как , работают нормально.

ОБНОВЛЕНИЕ В качестве обходного пути я просто переместил свой код, который требовал, чтобы сборка выполнялась с другой стороны (внутри домена), а затем возвращала строку назад, которая отлично маршала. Однако я буду держать вопрос открытым, потому что я хочу знать, есть ли решение для актуальной проблемы.

+0

Ну, вы снова вернулись на квадрат, потому что сборка теперь загружена в _both_ AppDomains, и вы можете только «Unload()» один из них. Почему бы не сделать все, что нужно сделать во вторичном AppDomain? – MickyD

+0

@MickyD Согласно обновлению вопроса, это то, что я закончил делать. Но мне это не нравится:/ – zaitsman

+0

Не нравится? В этом весь смысл AppDomains. Создание Appdomain для изоляции для загрузки говорит, что сборка или плагин только для возврата в родительский домен поражает цель песочниц точно так же, если вы создали дочерний поток для выполнения длительной задачи, но только для того, чтобы заблокировать его до завершения , Есть несколько хороших статей, которые я предлагаю вам прочитать в доменах MSDN Magazine re app – MickyD

ответ

0

Ну, конечно, вам нужно переместить код, который должен работать с сборкой, на отдельный AppDomain. Магии нет - если вам нужно работать с типом из ссылочной сборки, вам нужно загрузить эту сборку.

Существует два основных способа сортировки объектов через границы AppDomain (и другие сценарии удаленного доступа): либо вы создаете копию объекта, либо маршируете все вызовы методов. Оба очень сложны - вы должны убедиться, что вы никогда не просачиваете типы, находящиеся в указанной сборке, в противном случае вам нужно загрузить его в и домены. В вашем случае вы не можете маршалировать вызовы метода, потому что Assembly is не (и не может быть) MarshalByRefObject - ваш прокси должен вернуть реальный объект Assembly и не может создать маршаллирующий прокси.

Чтобы получить надлежащую изоляцию, вы должны избегать утечки любых типов из сборок, которые вы не хотите использовать, а также немаршируемых типов, которые могут выявить любые из них. Обычно это означает придерживаться примитивов и типов из общей библиотеки, если вы можете себе это позволить. Держите хороший жесткий интерфейс и старайтесь не использовать «автоматическую» сортировку слишком много - возврат автоматического прокси к сложному объекту удобен, но значительно затрудняет понимание области интерфейса. Есть ли у объекта метод, возвращающий тип из не разделяемой сборки? Слишком плохо, вам нужно загрузить его в свой домен.

В целом, работа с несколькими приложениями, которые фактически взаимодействуют (и связанные с ними удаленные .NET-объекты), представляет собой огромную боль.Это сложный, склонный к ошибкам и довольно трудно получить право. Вы можете читать целые книги по этому предмету. Есть причина, по которой их использование больше не рекомендуется - и почему они не поддерживаются в PCL (и в течение длительного времени не поддерживались в Mono). Они все еще полезны? Да. Изоляция программного обеспечения имеет очень хорошие преимущества. Но вам нужно быть очень осторожным, чтобы не повредить вещи :)

+0

_ «Это сложно, склонно к ошибкам и довольно трудно получить право. Вы можете читать целые книги по теме» _ - возможно. Вы можете сказать то же самое и о шифровании; безопасность на основе требований; VS языковые службы и визуальное распознавание. Не означает, что мы не должны сдаваться только из-за нескольких плохо написанных книг. Что касается AD, я нашел несколько блестящих статей MSDN за 2006 год, которые очень помогли мне – MickyD

+0

@MickyD Yup, я не говорю, что вы не должны его использовать. Я говорю, вам нужно многому научиться, и убедитесь, что вы делаете это правильно. Вы обнаружите, что для многих случаев, когда вы звоните в домены приложений, вы можете найти лучшее решение. И в идеале, избегайте прямого доступа к ним - программисту ASP.NET почти никогда не нужно думать о доменах приложений, хотя они очень важны для программ ASP.NET. Так же, как вы не будете писать свой собственный алгоритм шифрования - вы используете самую высокую абстракцию, которая фактически решает вашу проблему. – Luaan

+0

Я согласен с этим, потому что в философском вопросе правильный ответ - 'Assembly' не является' MarshalByRefObject' и загружается, таким образом, в оба домена приложения. Чтобы обойти это, я сделал всю работу в дочернем домене приложения. – zaitsman