C#, MAF, управление необработанными исключениями в отдельном домене приложений
Итак, у меня есть приложение MAF, которое загружает каждое дополнение внутри отдельного домена приложения. Это работает фантастически для того, что мне нужно, так как позволяет динамически выгружать и перезагружать надстройки во время выполнения.
Проблема в том, что мне нужно иметь возможность сделать необработанное исключение в дочернем домене приложения, перехватить его, а затем позволить этому домену изящно завершить работу, не удаляя родительский домен приложения.
Как мне это сделать? Это кажется тривиальной задачей и одним из основных преимуществ использования изолированных доменов приложений...
3 ответа
Я думаю, что мой ответ на этот похожий вопрос должен помочь вам:
Сбой приложения при выдаче исключения другим доменом
Дайте мне знать, если вам нужна дополнительная информация.
Насколько я знаю, вы не можете сделать это из коробки. Вы можете использовать абстрактные классы для представлений надстроек и добавлять блоки try/catch повсюду в сочетании с шаблоном Template Method (т. Е. Метод Read в абстрактном представлении надстройки вызывает виртуальную функцию ReadCore, которую должна реализовать надстройка). Тем не менее вы не можете обрабатывать необработанные исключения, создаваемые дочерними потоками дочернего домена приложения. Это приведет к краху вашего приложения.
Опять же, насколько я знаю, есть два способа решения этой проблемы:
- Используйте изоляцию процесса. Это единственный способ быть уверенным, что надстройки не приведут к краху хоста.
- Следуйте подходу, описанному в статье Использование изоляции домена приложения для обнаружения сбоев надстроек из
System.AddIn
блог команды. Этот подход не может предотвратить сбой вашего приложения, но ваше приложение будет знать, какая надстройка вызвала сбой. Это ценная информация, потому что тогда ваше приложение может отключить нестабильные надстройки и не загружать их при следующем запуске. Или приложение может сообщить пользователю и позволить ему / ей решить, что делать.
Обратите внимание, что эти два дополняют друг друга. Вы можете начать с 2., а затем загружать нестабильные надстройки в различные процессы.
Завелась с подходом, который сегодня, похоже, работает отлично, хотя мне еще нужно кое-что сделать, прежде чем я узнаю о последствиях этого подхода...
Следующее сообщение в блоге очень помогло: http://ikickandibite.blogspot.com/2010/04/appdomains-and-true-isolation.html
Я просто включил устаревшую политику необработанных исключений в app.config:
(который, как FYI, все еще доступен даже в.Net 4.5, который меня беспокоил)
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<runtime>
<legacyUnhandledExceptionPolicy enabled="true"/>
</runtime>
</configuration>
... С этого момента я могу использовать событие AppDomain.UnhandledException, чтобы перехватить необработанное исключение и выгрузить субдомен... (обратите внимание, что я говорю "перехватить" здесь свободно... Я все еще не "ловлю" исключение, просто принимая к сведению выгрузку надстройки в процессе)
Collection<AddInToken> tokens = AddInStore.FindAddIns(typeof(IApplicationAddIn), pipelineStoreLocation, addInPath);
foreach (AddInToken token in tokens)
{
AppDomain domain = AppDomain.CreateDomain(token.Name);
domain.UnhandledException += (sender, args) =>
{
AppDomain _domain = (AppDomain) sender;
AppDomain.Unload(_domain);
};
Console.WriteLine("Initializing add-in '{0}'", token.Name);
IAddIn addin = token.Activate<IAddIn>(domain);
try
{
addin.Initialize(this);
}
catch (Exception ex)
{
Console.WriteLine("Problem initializing add-in '{0}': {1}", token.Name, ex.Message);
}
}