Я создал простой ASP.NET приложение версии 1.0 MVC. У меня есть ProductController, который имеет один Индекс действия. В представлении я создал соответствующий Index.aspx под подпапкой продукта.
Затем я сослался на Spark dll и создал Index.spark под той же папкой Обзора продукта. Application_Start похож
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new Spark.Web.Mvc.SparkViewFactory());
ViewEngines.Engines.Add(new WebFormViewEngine());
}
Мое ожидание состоит в том, что начиная с регистров механизма Spark, прежде чем WebFormViewEngine по умолчанию, когда просматривают Индексное действие в контроллере продукта, механизме Spark, должен использоваться, и WebFormViewEngine должен использоваться для всех других URL.
Однако тест показывает, что Индексное действие для контроллера продукта также использует WebFormViewEngine.
Если я комментирую регистрацию WebFormViewEnginer (последняя строка в коде), я вижу, что Индексное действие представляется механизмом Spark и остальными, URL генерируют ошибку (так как defualt механизма не стало), оказывается, что весь мой код Spark является правильным.
Теперь мой вопрос состоит в том, как механизм представления разрешен? Почему регистрационная последовательность не вступает в силу?
Порядок, в котором вы регистрируете механизмы просмотра, не имеет значения (много). Скорее, механизмы просмотра принимают набор ViewLocationFormats
, и если конкретный путь просмотра соответствует форматированному имени, этот механизм будет использоваться. Порядок регистрации имеет значение только при наличии конфликтующих форматов.
В случае искры представления должны иметь расширение .spark
. WebFormViewEngine
ответит на все с расширениями .aspx
или .ascx
. И, конечно же, как упоминалось выше, вы можете отменить любое из этого, изменив ViewLocationFormats
, предоставленный отдельным механизмам просмотра.
Обновлено:
Я просмотрел источник как SparkViewFactory
, так и WebFormViewEngine
(или, более конкретно, VirtualPathProviderViewEngine
, который является производным от ), и я могу сказать вам, почему вы наблюдаете такое странное поведение.
Прежде всего, метод Find
в классе ViewEngineCollection
работает следующим образом (упрощенно):
foreach (IViewEngine engine in Items) {
// Query engine for cached view
}
foreach (IViewEngine engine in Items) {
// Query engine for uncached view
}
Другими словами, он всегда будет пытаться найти кэшированное представление, в любой движок , прежде чем переходить в некэшированный режим.
Способ, которым отдельные механизмы просмотра реализуют это, является второй перегрузкой метода FindView
, который принимает аргумент bool
с именем useCache
.
Однако , и вот где все это становится странным - VirtualPathProviderViewEngine
и SparkViewEngine
имеют очень разные представления о том, что означает аргумент useCache
. Здесь слишком много кода для повторной публикации, но основная идея такова:
SparkViewFactory
будет искать только в кэше, если useCache
имеет значение true
. Если ничего не находит, автоматически возвращается «результат промаха кеша», то есть ничего. С другой стороны, если useCache
имеет значение false
, он вообще не будет смотреть в кеш, он пропустит этап проверки кеша и выполнит обычные действия для разрешения и создания реальный вид.
VirtualPathProviderViewEngine
, с другой стороны, просматривает кеш, если useCache
имеет значение true
, и если он не находит представление в кеше , он отключается, создает новый и добавляет его в кеш.
Оба этих подхода работают по отношению к тому, как ViewEngineCollection
выполняет поиск.
В случае искры он «промахивается» на первой итерации механизмов просмотра, но «попадает» на второй, и после этого представление добавляется в кэш. Без проблем.
В случае VirtualPathProviderViewEngine
он «пропускает» внутренне, но все равно возвращает «попадание» на первой итерации, после чего представление теперь кэшируется.
Итак, вы должны увидеть, в чем проблема. VirtualPathProviderViewEngine
только , похоже, имеет приоритет над SparkViewEngine
, потому что первый всегда преуспевает на первой (кэшированной) итерации, но Spark успешно выполняется только на второй (некэшированной) итерации.
Говоря простым языком, Spark действительно сначала спрашивают, но он отвечает: «Нет, у меня еще нет такого представления . Попробуйте вместо этого без кеша». WebForms получает второй вопрос, но автоматически говорит «У меня не было такого мнения, но я все равно пошел и сделал его для вас, вот оно» . И с этого момента WebFormViewEngine
всегда получает приоритет, потому что у него кешируется представление, а у Spark нет.
Резюме: Spark получает приоритет, но из-за причуды в том, как Spark обрабатывает аргумент useCache
, он теряется, когда движок веб-форм активен в в то же время. Либо WebForm чрезмерно нетерпелив, либо Spark ленив, в зависимости от вашей точки зрения.
Проще говоря, решение состоит в том, чтобы не иметь противоречивых взглядов! Если вы зарегистрировали несколько механизмов просмотра, то вам следует рассматривать любое имя представления, которое может обрабатываться одним / обоими из них, как undefined behavior .
Хммм ... Нет, при всем уважении, веб-формы не делают ничего, кроме проверки кеша, когда useCache имеет значение true. То же, что и Spark.
На самом деле - я думаю, что кто-то мог переместить мой сыр ... В Spark могла быть добавлена причуда, вызывающая ложную ошибку кеширования во время прохода useCache == true. Если это правда, то это скорее ошибка, чем другие правила, применяемые к этому параметру.
Обновлено:
Изначально я смотрел на MVC 2 - поэтому я предположил, что выводы @Aaronaught неверны. MVC 2 не возвращает представление на первом проходе, где useCache == true, что отличается в MVC 1.0, который разрешает и заполняет.
Таким образом, разница между способами реализации ASP.NET MVC 1.0 и ASP.NET MVC 2. Spark и MVC 2 одинаково обрабатывают флаг useCache, и порядок их регистрации дает им приоритет.