ОБНОВЛЕНИЕ: хорошо, как вы обнаружили, циклическая ссылка была неправильным предположением, так как существуют другие ситуации, которые могут вызвать подобное поведение.
Более общий способ описания проблемы состоит в том, что пакетирование во время выполнения работает очень разрешающим способом, который может маскировать проблемы. По сути, мы пытаемся пакетировать все в одной папке, но если мы получаем ошибку компиляции при компиляции этого пакета, мы возвращаемся к компиляции отдельных файлов. Во многих случаях это работает нормально, но иногда это может привести к двойной компиляции данной страницы (аналогично тому, что я описал ниже, но по другой причине).
С другой стороны, aspnet_compiler работает строго , где при сбое пакетирования происходит сбой и не происходит откат. Вот почему запуск этого инструмента является отличным способом обнаружения проблем различного типа (или скрытых проблем), которые могут быть далеко не очевидны во время выполнения. Я думаю, мы не проделали хорошую работу по пропаганде этого инструмента для этой цели:)
Что касается того, почему переименование файла исправило его, это может быть вызвано тем, что он изменил порядок обработки файлов, что является немного произвольным. Может случиться так, что если вы переименуете его во что-то другое, вы увидите, что это случится снова.
Честно говоря, оглядываясь назад, я как бы хотел, чтобы во время выполнения мы установили строгий режим пакетной обработки, чтобы уловить эти ситуации раньше. Причиной, по которой мы выбрали нынешний запасной дизайн, было недопущение сбоев, когда это было возможно, но это было связано с ценой: когда что-то не так, уловить боль очень сложно:)
ОРИГИНАЛЬНЫЙ ОТВЕТ:
Короче говоря, проблема в том, что когда пакетная обработка включена (и это по умолчанию), вы должны избегать циклических зависимостей на уровне каталогов. Позвольте мне объяснить, что я имею в виду под этим.
Вот пример. Скажем, у вас есть:
- В папке 1: page.aspx и uc2.ascx
- In forder2: uc1.ascx
И скажем, что page.aspx ссылается на uc1.ascx (через директиву @register), а uc1.ascx ссылается на uc2.ascx. На уровне файлов это прекрасно, но на уровне каталогов существует круговая зависимость: папка 1 ссылается на что-то в папке 2, которая ссылается на что-то в папке 1.
Почему это проблематично, связано с тем, как работает пакетирование: когда вы запрашиваете страницу, она сначала пытается скомпилировать все в папке folder1. Но так как folder1 / page.aspx ссылается на folder2 / uc1.ascx, он должен скомпилировать folder2, прежде чем он сможет сделать folder1. Но тогда uc1 использует uc2, то есть сначала он должен сделать folder1! На этом этапе ASP.NET обнаруживает ситуацию и пытается извлечь из нее выгоду, откомпилировав uc2.asc самостоятельно. Хотя это позволяет работать некоторым сценариям, оно также может вызывать странные вещи, потому что некоторые элементы в конечном итоге скомпилированы в две сборки. Здесь uc2.ascx будет скомпилирован как сам, так и с пакетом folder1.
Существует способ легко определить, есть ли у вашего сайта такие циклические зависимости на уровне папок. В окне консоли VS перейдите в корень сайта и запустите:
aspnet_compiler -v foo -p .
Если у вас круговые зависимости на уровне папок, вы получите несколько ошибок, которые выглядят следующим образом:
/foo/Sub/UC1.ascx(2): error ASPPARSE: Circular file references are not allowed.
Дешевый способ избежать этой проблемы - это то, что вы уже знаете: отключить пакетирование. Теперь, по крайней мере, вы знаете, почему это работает:)
Но лучше по возможности избегать циклических зависимостей на уровне папок. Если вы начинаете думать о каждой папке как о «компоненте», который создает сборку, это действительно имеет смысл и может помочь сделать части вашего сайта более модульными.
Да, также справедливо назвать это «ошибкой» в системе компиляции или, по крайней мере, ограничением. Но как только вы узнаете об этом, этого довольно легко избежать.