问题
I have an ASP.NET site with both WebForms and MVC sections to it. When I try to precompile the site, everything works except serving images/css from under App_Themes.
If I request something like /foo/App_Themes/themeName/my.png
, I get this error:
The file '/foo/App_Themes/themeName/my.png.cshtml' is in the special directory 'App_Themes', which is not allowed.
I only get this when precompiling, it works fine otherwise. Presumably MVC routing is interfering somehow, but I don't know why or how to disable it.
In case it's helpful, here's the stack trace:
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:
I was having the same issue but it only occured when I published my web application and would work fine locally. I came up with two potential solutions.
Hacky solution
By looking at the source code I could see it was throwing this error as the "BuildManager" object had a field "_forbiddenTopLevelDirectories" which it would check and throw an expection if the path was in a number of special directories, "App_Themes" being one of them.
So by using reflection I remove the "App_Themes" object from the collection by calling the following code in the global file Application_Start
method.
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" });
This solved the issue and my css + image files would now be correctly served when deployed. Warning - I do not have a good understanding of the consequences of editing the _forbiddenTopLevelDirectories
field and doing this may have unintended side effects.
Alternative solution
Another thing i noticed was I would not recieve the errors when the runAllManagedModulesForAllRequests attribute of the modules node in the webconfig was set to false. So if your application can work with this set to false consider this solution
<modules runAllManagedModulesForAllRequests="false">
来源:https://stackoverflow.com/questions/21268124/getting-an-error-serving-images-from-app-themes-when-using-precompilation