Почему ASP.NET по-разному разрешает ссылки на сборки?
Я действительно изо всех сил пытался найти похожую проблему, чтобы привлечь некоторых клиентов, но никто, кажется, не описывает описанный нами случай, так что вот так.
Фон
У нас есть продукт со следующим общим дизайном:
[Локальная папка установки]
- Содержит набор сборок.NET, реализующих основную часть функциональности нашего продукта.
- Пример: Реализация1.dll, Реализация2.dll
[ПКК]
- ClientAPI.dll. Наша клиентская сборка, на которую нужно ссылаться из проектов Visual Studio конечного пользователя. Имеет сильные ссылки на реализацию DLL в локальной папке установки.
В ClientAPI.dll у нас есть точка входа, для запуска которой требуются проекты конечного пользователя. Давай называть это Initialize()
,
Самое первое, что мы делаем в Initialize
установить так называемый обработчик разрешения сборки в текущем домене, используя AssemblyResolve
событие. Этот обработчик будет знать, как найти библиотеки реализации и загрузить их в клиентский процесс, используя Assembly.Load()
,
Рассмотрим консольное приложение. Это будет выглядеть примерно так:
class Class1
{
void Main(string[] args)
{
ClientAPI.Initialize();
// Use other API's in the assembly, possibly internally referencing the
// implementation classes, that now will be resolved by our assembly
// resolve handler.
}
}
Теперь все хорошо в мире консоли / Windows Forms/WPF. Наш обработчик разрешения сборки правильно установлен и вызван, и он может успешно разрешать ссылки на библиотеки DLL реализации, когда ClientAPI.dll требует их функциональности.
Постановка задачи
С учетом вышесказанного мы намерены не поддерживать только консольные или WPF-приложения, поэтому мы полагались на тот же дизайн в ASP.NET. Следовательно, создав новый проект веб-приложения ASP.NET в VS 2010, мы решили, что все будет так же просто, как:
class Globals : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
ClientAPI.Initialize();
// ...
}
}
За 20-30 часов пребывания во вселенной времени выполнения ASP.NET, попробовав вышесказанное как на сервере разработки, так и в IIS, мы поняли, что на самом деле все не так, как мы ожидали.
Оказывается, в ASP.NET, как только ClientAPI
ссылка на класс в любом месте, все ссылки, которые он имеет на любые другие сборки, немедленно разрешаются. И не только это: результаты кэшируются (по замыслу, начиная с.NET 2.0, которую мы обнаружили), а это означает, что у нас никогда не было шансов вообще помочь CLR.
Без дальнейшей проработки различных вещей, которые мы попробовали и изучили, все сводится к следующему вопросу:
Почему ASP.NET разрешает ссылки так? Это несовместимо с тем, как это делают другие типы приложений, и, более того, это не соответствует документации среды выполнения.NET / CLR, в которой указывается, что ссылки на внешние типы / сборки должны разрешаться при первой необходимости (т.е. когда впервые используется в коде).
Любые идеи / идеи будут высоко оценены!
1 ответ
Приложения Windows Forms / WPF выполняются на отдельных клиентских компьютерах (и, следовательно, выполняются в одном локальном контексте), тогда как ASP.Net работает в IIS, в пуле приложений, на сервере или наборе серверов (в ситуации веб-фермы). Все, что загружено в пул приложений, доступно всему приложению (и поэтому распределяется между всеми клиентами, которые подключаются к приложению).
HttpApplication.Application_Start выполняется один раз, когда приложение запускается. Он не выполняется для каждого клиента, как это было бы с приложением Winforms - если вам нужно что-то инициализировать для каждого подключаемого клиента, используйте Session_Start или Session_OnStart, но затем вы можете столкнуться с проблемами памяти на сервере, в зависимости от того, сколько клиентов собираетесь подключиться к вашему веб-приложению. Это также зависит от того, является ли ваш класс одноэлементным, и является ли метод Initialize() статическим. Если у вас возникнет какая-либо из этих ситуаций, вы довольно быстро столкнетесь с проблемами многопоточности.
Кроме того, стоит отметить, что неиспользуемый пул приложений IIS будет сброшен через некоторое время. Например, если никто не использует веб-приложение в одночасье, IIS очистит пул приложений и освободит память. Эти параметры можно изменить в рамках администрирования IIS, но при этом следует соблюдать осторожность - изменение этих параметров для обхода плохо спроектированного объекта (или объекта, не предназначенного для веб-приложения) может создать еще больше проблем.
К вашему сведению - я немного суетлив, но во избежание сомнений, объект не кэшируется - да, он загружается в память, но как управление памятью зависит от того, как вы спроектировали объект (кэширование в веб-мире это совсем другое дело, и может быть реализовано на разных уровнях вашего приложения).
Не пытайтесь заставить веб-приложение вести себя как приложение для Windows; вы просто создадите себе больше проблем!