Получаете ли вы ошибку при доставке изображений из App_Themes при использовании прекомпиляции?
У меня есть сайт ASP.NET с разделами WebForms и MVC. Когда я пытаюсь предварительно скомпилировать сайт, все работает, кроме обслуживания images/css из-под App_Themes.
Если я прошу что-то вроде /foo/App_Themes/themeName/my.png
Я получаю эту ошибку:
The file '/foo/App_Themes/themeName/my.png.cshtml' is in the special directory 'App_Themes', which is not allowed.
Я получаю это только при прекомпиляции, иначе работает нормально. Предположительно, маршрутизация MVC как-то мешает, но я не знаю, почему и как это отключить.
В случае, если это полезно, вот трассировка стека:
System.Web.Compilation.BuildManager.ValidateVirtualPathInternal(VirtualPath virtualPath, Boolean allowCrossApp, Boolean codeFile) +9930801
System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate) +455
System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate) +103
System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean throwIfNotFound) +165
System.Web.Compilation.BuildManager.GetObjectFactory(String virtualPath, Boolean throwIfNotFound) +33
System.Web.WebPages.BuildManagerWrapper.GetObjectFactory(String virtualPath) +26
System.Web.WebPages.BuildManagerWrapper.ExistsInPrecompiledSite(String virtualPath) +80
System.Web.WebPages.BuildManagerWrapper.Exists(String virtualPath) +13
System.Web.WebPages.<>c__DisplayClass1.<Exists>b__0(IVirtualPathFactory factory) +15
System.Linq.Enumerable.Any(IEnumerable`1 source, Func`2 predicate) +146
System.Web.WebPages.VirtualPathFactoryManager.Exists(String virtualPath) +73
System.Web.WebPages.DefaultDisplayMode.GetDisplayInfo(HttpContextBase httpContext, String vir tualPath, Func`2 virtualPathExists) +42
System.Web.WebPages.<>c__DisplayClassb.<GetDisplayInfoForVirtualPath>b__8(IDisplayMode mode) +22
System.Linq.WhereSelectListIterator`2.MoveNext() +104
System.Linq.Enumerable.FirstOrDefault(IEnumerable`1 source, Func`2 predicate) +94
System.Web.WebPages.DisplayModeProvider.GetDisplayInfoForVirtualPath(String virtualPath, HttpContextBase httpContext, Func`2 virtualPathExists, IDisplayMode currentDisplayMode, Boolean requireConsistentDisplayMode) +204
System.Web.WebPages.WebPageRoute.GetRouteLevelMatch(String pathValue, IEnumerable`1 supportedExtensions, IVirtualPathFactory virtualPathFactory, HttpContextBase context, DisplayModeProvider displayModeProvider) +201
System.Web.WebPages.WebPageRoute.MatchRequest(String pathValue, IEnumerable`1 supportedExtensions, IVirtualPathFactory virtualPathFactory, HttpContextBase context, DisplayModeProvider displayModes) +281
System.Web.WebPages.WebPageRoute.DoPostResolveRequestCache(HttpContextBase context) +235
System.Web.WebPages.WebPageHttpModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +89
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +136
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69
1 ответ
У меня возникла та же проблема, но она возникла только тогда, когда я опубликовал свое веб-приложение, и работал бы хорошо локально. Я придумал два возможных решения.
Хакерское решение
Просматривая исходный код, я увидел, что он выдает эту ошибку, поскольку объект "BuildManager" имеет поле "_forbiddenTopLevelDirectories", которое он проверяет и выдает исключение, если путь находится в ряде специальных каталогов, "App_Themes" является из них.
Поэтому, используя отражение, я удаляю объект App_Themes из коллекции, вызывая следующий код в глобальном файле. Application_Start
метод.
var buildManagerType = typeof(BuildManager);
var theBuilderManager = buildManagerType.GetField("_theBuildManager"
, BindingFlags.Static | BindingFlags.NonPublic)
.GetValue(null);
var forbiddenDirectoryField = buildManagerType
.GetField("_forbiddenTopLevelDirectories",
BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(theBuilderManager);
var removeMethod = forbiddenDirectoryField.GetType().GetMethod("Remove");
removeMethod.Invoke(forbiddenDirectoryField, new object[] { "App_Themes" });
Это решило проблему, и мои файлы изображений css + теперь будут правильно обслуживаться при развертывании. Предупреждение - у меня нет хорошего понимания последствий редактирования _forbiddenTopLevelDirectories
поле и выполнение этого может иметь непредвиденные побочные эффекты.
Альтернативное решение
Еще одна вещь, которую я заметил, это то, что я не получаю ошибки, когда атрибут runAllManagedModulesForAllRequests узла modules в webconfig был установлен в false. Поэтому, если ваше приложение может работать с этим набором false, рассмотрите это решение.
<modules runAllManagedModulesForAllRequests="false">