Хорошая архитектура / библиотека для надежного управления плагинами / надстройками
У нас есть приложение, которое, в качестве одного из требований, будет принимать произвольные сторонние плагины, загружать их и запускать их пользовательский интерфейс вместе с нашим собственным приложением. Мы загружали эти сторонние плагины в свои собственные домены приложений в целях изоляции, и все работает нормально.
Пока один из плагинов не выходит из строя с необработанным исключением. В этом случае все приложение отключается, хотя все, что действительно затронуто, - это одно из наших "дополнительных" окон инструментов.
В идеале нам нужен какой-то способ обработки "необработанного" исключения, выгрузки поврежденного AppDomain, а затем просто перезагрузки. Проблема в том, что мы не можем найти механизм в обработчике событий для необработанного исключения, посредством которого мы можем пометить исключение как "обработанное". Кроме того, поскольку плагины имеют свои собственные компоненты пользовательского интерфейса со своим собственным набором взаимодействий с пользователем, было бы чрезвычайно трудно "обернуть" наши взаимодействия с плагинами в блоки try / catch / finally.
Существуют ли какие-либо фреймворки / библиотеки / шаблоны программирования, которые поддаются решению этой проблемы? Мы можем сделать плагин хорошо; нам нужна помощь в поддержании работы приложения, когда код в другом домене приложений неожиданно завершается с ошибкой.
5 ответов
Вы можете использовать System.Addin
рамки (иногда известный как MAF
), что немного затрудняет правильную настройку, но было разработано для обеспечения изоляции (защита от сбоев). System.Addin
основан на удаленном взаимодействии. С помощью этой среды вы можете позволить плагинам запускаться с ограниченными разрешениями в том же процессе, или в другом домене приложения, или даже в другом процессе.
Если вам нужна полная защита от сбоев, вам, возможно, придется использовать опцию разделения процессов. Это может прийти за счет производительности, хотя.
Вы можете использовать этот код для загрузки надстройки в другом домене приложения:
AppDomain addInDomain = AppDomain.CreateDomain("addin domain");
// addInDomain.PermissionSet = ...
AddInEnvironment env = new AddInEnvironment(addInDomain);
// Activate the add-in
IHostView addinInstance = addinToken.Activate<IHostView>(env);
Console.WriteLine(addinInstance.DoSomething());
AppDomain.Unload(addInDomain);
Если вы хотите загрузить надстройку в другой процесс, для полной изоляции:
AddInProcess process = new AddInProcess();
process.Start();
// Activate the add-in
IHostView addinInstance = addinToken.Activate<IHostView>(process, AddInSecurityLevel.Internet);
try
{
// use a catch block, prevent exceptions from the addin crashing the main app
Console.WriteLine(addinInstance.DoSomething());
}
catch (Exception e)
{
Console.WriteLine(e);
}
process.Shutdown();
Этот блог дает хорошее описание настройки этого.
Можно комбинировать System.Addin
с MEF это бесплатные наборы инструментов, см. эту статью.
Обратите внимание, что модель System.Addin может обеспечить защиту от сбоев, вам все равно придется иметь дело с замедлениями или взаимоблокировками в коде надстройки. Асинхронное использование поможет здесь.
Я бы пошел с MEF
Я не думаю, что это возможно. Насколько я понимаю, что даже если вы обработаете событие AppDomain.UnhandledException, приложение все равно прекратит работу. Лучшее, что вы можете сделать - это обработать исключение, записать, что вы можете, сохранить то состояние, в котором вы можете, и завершить работу корректно.
Похоже, вы хотите что-то похожее на OSGi для Java - MEF OSGi для.NET? Похоже, это может соответствовать всем требованиям.
Я предполагаю, что вы уже проверили документацию thourougly, но если не на следующей странице
http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx
действительно предоставляет много информации о том, как работают необработанные исключения. Он также упоминает несколько атрибутов, которые позволяют точно настроить поведение.
К сожалению, я не могу дать вам никаких советов по вашей конкретной ситуации, так как я не использовал отдельные домены приложений таким образом. Что я могу сказать, так это то, что из моего опыта с событием UnandledException флаг IsTerminating редко бывает истинным, и мы почти всегда можем восстановиться после необработанного исключения.