2010-04-03 3 views
8

Я использую настраиваемую фреймворк, который использует отражение, чтобы сделать GetTypeByName(string fullName) на полностью квалифицированном имени типа, которое он получает из базы данных, чтобы создать экземпляр указанного типа и добавить его в страница, в результате чего появилась стандартная модульная вещь.Сборка недоступна после изменения Web.config

GetTypeByName является моей полезной функцией, которая просто выполняет итерации через Thread.GetDomain().GetAssemblies(), а затем выполняет assembly.GetType(fullName), чтобы найти соответствующий тип. Очевидно, что этот результат будет кэшироваться для дальнейшего использования и скорости.

Однако у меня возникают некоторые проблемы, при которых обновляется web.config (и в некоторых более страшных случаях, если пул приложений получает рециркуляцию), он потеряет все знания определенных сборок, что приведет к невозможности визуализации экземпляр типа модуля. Отладка показывает, что отсутствующая сборка буквально не существует в списке текущих сборок потоков.

Чтобы обойти это, я добавил вторую проверку, которая немного грязна, но рекурсирует через DLL-файлы/bin/directory и проверяет, что каждый из них существует в списке сборок. Если это не так, он загружает его с помощью Assembly.Load и исправляет проблему контекста благодаря 'Solving the Assembly Load Context Problem'.

Это будет работать, только кажется, что (и я знаю, что это не должно быть возможным), некоторые проекты все еще имеют доступ к отсутствующей сборке, например, мой фактический веб-проект, а не сама фреймворк, а затем жалуется, что дубликаты ссылок были добавлены!

Кто-нибудь слышал о чем-либо подобном, или есть идеи, почему сборка просто выпадет из существования при изменении конфигурации? Какое из самых элегантных способов решения проблемы позволяет собрать все сборки в бункере? Это должно быть все в одном «хите», чтобы посетители сайта не видели никакой разницы, кроме небольшой задержки, поэтому файл app_offline.htm не может быть и речи. Программно переименовать DLL в бункер, а затем именовать его, работает, но требует «изменить» разрешения для учетной записи пользователя IIS, что является безумным.

Спасибо за любые указания, которые сообщество может собрать!

+0

@ tags2k Можно поместить ссылку для загрузки DLL-файла, который создает проблему, чтобы проверить его с помощью отражателя, в точке ошибки (также на GetTypeByName). – Aristos

ответ

2

Как правило, вам не следует полагаться на то, какие сборки в настоящее время загружаются в appdomain, поскольку это происходит динамически. Вместо этого просто вызовите System.Web.Compilation.BuildManager.GetType() вместо Type.GetType() или Assembly.GetType(). Это должно делать правильное дело для вас, и не должно быть затронуто циклами appdomain.

+0

Спасибо, Дэвид, я никогда раньше не слышал об этом классе, но это просто помогло моему прикладу большого времени! Большое спасибо - вот ваша щедрость! : D – tags2k

+0

Рад, что я мог помочь! Думаю, мы не очень хорошо документировали различные методы BuildManager. Я постараюсь сделать кое-что из блога. :) –

+0

Отличный совет, но что вам делать, если вы хотите реализовать реализацию данного интерфейса, а не конкретный жесткий код? Например: 'typeof (IStuff) .IsAssignableFrom (type) &&! Type.IsInterface'. –

1

Я никогда не слышал об этой проблеме раньше.

Я не уверен, что это сработает, поскольку я только недавно прочитал об этом, исследуя обходные пути для зависимостей ODAC, но указание пути обнаружения для сборок может решить вашу проблему.

см: http://msdn.microsoft.com/en-us/library/823z9h8w(VS.80).aspx

образец:

<configuration> 
    <runtime> 
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
     <probing privatePath="bin;bin2\subbin;bin3"/> 
     </assemblyBinding> 
    </runtime> 
</configuration> 
+0

Спасибо за идею Джима, но, к сожалению, это не помогло. Я даже попытался сделать копию мусорного ведра и сказать, чтобы посмотреть там, но безрезультатно! – tags2k

1

У меня аналогичная проблема, когда я обновляю 2-5 файлов, эфир web.config, эфир и другие файлы, и asp.net необходимо воссоздать запущенные файлы, затем несколько раз не находили некоторые классы/функции, которые существуют в файлах dll, а моя система не работает - бросайте ошибки, подобные вашим.

Мое решение состоит в том, что я размещаю app_offline.htm на корне, делаю свои обновления, а затем переименую/удалю app_offline.htm, и моя система работает нормально.

Я уверен, что что-то связано с кэшированными скомпилированными файлами, но у меня не было никакого поиска, в чем именно причина.

[что это самый элегантный обходной путь, чтобы получить все узлы в бункере, чтобы перезагрузить]

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

http://msdn.microsoft.com/en-us/library/system.web.httpruntime.unloadappdomain(VS.80).aspx

Я не знаю, если это решить вашу проблему, вы должны сделать тесты.

вероятно на Global.asax сделать что-то вроде этого

void Application_Error(object sender, EventArgs e) 
{ 
    Exception ex = Server.GetLastError().GetBaseException(); 
    ...if ex is your error, and you get more than 2 ... 
    { 
    HttpRuntime.UnloadAppDomain(); 
    } 
} 
+0

Спасибо Аристосу! Приятно слышать, что я не единственный!Что касается вашего решения, я попытался реализовать это раньше с помощью перенаправления непосредственно перед вызовом, чтобы посетитель, который запускает перезагрузку, не замечает ничего, кроме небольшой задержки при запуске приложения. Тем не менее, я не уверен, что вызов UnloadAppDomain выполнил задание, так как у меня появилась страница «Объект, перемещенный сюда» без загрузки моего сайта. Я дам этому методу еще один выстрел. – tags2k

+0

да, пожалуйста, сделайте тест на этот метод. Я реализую этот метод и сам, и его работу, но я не знаю, что произойдет в вашем случае. – Aristos

+0

Hi Aristos, я попробовал это снова, но имел ту же проблему - без перенаправления Я получаю ошибку; если я перенаправляю пользователя, тогда я получаю страницу «объект, перемещенный сюда». Спасибо за ваш вклад. – tags2k

2

Как вы, очевидно, знаете, there are many situations where the current appdomain is unloaded and reloaded. После каждой перезагрузки все сборки выгружаются, и все приложение запускается «с нуля».

Ассембли по умолчанию загружаются по требованию. Обычно это тот случай, когда JIT натыкается на некоторую ссылку. В результате перезагрузка appdomain очистит сборки в appdomain, и они появятся снова позже, когда JIT загрузит их.

В качестве решения я бы воспользовался статическим методом Type.GetType() и предоставил квалифицированное имя сборки (например, имя типа с включенным именем сборки). Это то же самое, что использует платформа при загрузке типов, указанных в файле конфигурации, и она будет следить за тем, чтобы требуемая сборка была обыскана и загружена по требованию без использования каких-либо трюков. См. Раздел замечаний метода выше (имя метода над именем является ссылкой).

Это потребует обновлений в вашей базе данных, чтобы содержать только квалифицированные имена сборки, а не только «полностью» имена типов. Тем не менее, он также гарантирует, что вы не столкнетесь с конфликтами имен, когда две сборки предоставляют разные типы с тем же именем, поэтому это хорошая идея, так или иначе.

+0

Моя проблема с использованием 'Type.GetType()' (и причина, по которой я не решал ее на начальном этапе проектирования), заключалась в том, что если я буду хранить имя типа версии 1.1.0.0 сборки и затем перейти на версию 1.1.0.1, у меня не осталось ни одного из предыдущих модулей. Когда я не могу больше загружать тип, потому что это другая версия, мне нужно использовать еще более грязные трюки, чтобы повторно ссылаться на модули в правильной версии. Есть ли способ хранения пространства имен таким образом, чтобы он позволял любую будущую версию сборки? – tags2k

+0

Да, просто оставьте версию. Это, по крайней мере, будет работать для сборок, которые не имеют сильного имени. Или вы можете добавить перенаправления ассемблерной версии с помощью политики. http://msdn.microsoft.com/en-us/library/7wd6ex19.aspx – Lucero

+0

Поскольку информация о версии идет .net связывается с версией сборки DLL, где в качестве окон и MSI используются файлы версий. Вы можете увеличить версию файла независимо от версии сборки, чтобы привязка .net не прерывалась после каждой новой сборки. Например: номер вашей версии сборки может оставаться на уровне 1.1.0.0, а номер версии вашего файла может увеличивать номер сборки после каждой сборки. –

0

Я бы попытался создать базовый класс, из которого интересна для вас сборка без отражения в приложении. Начните, чтобы убедиться, что она загружена. .

var temp = new BaseModuleBuilder(); 

Это не выглядит умным, но это очень странно, и asp.net должен делать все для вас. В случае, если ваш список слишком динамична, это может быть что-то вроде

var temp = Activator.CreateInstance(Type.GetType("BaseModuleBuilder, Modules.dll")); 

Убедитесь, что всегда указывать DLL при работе с dynacmically загруженных классов.

+0

Спасибо, Сергей, но это невозможно, так как для этого потребуется ссылка на круговую сборку! – tags2k

Смежные вопросы