internal override void CacheBuildResult(string cacheKey, BuildResult result, long hashCode, DateTime utcStart) { if (!(result is BuildResultCompiledTemplateType)) { base.CacheBuildResult(cacheKey, result, hashCode, utcStart); } }
internal override void CacheBuildResult(string cacheKey, BuildResult result, long hashCode, DateTime utcStart) { if (!BuildResultCompiledType.UsesDelayLoadType(result)) { ICollection virtualPathDependencies = result.VirtualPathDependencies; CacheDependency dependencies = null; if (virtualPathDependencies != null) { dependencies = result.VirtualPath.GetCacheDependency(virtualPathDependencies, utcStart); if (dependencies != null) { result.UsesCacheDependency = true; } } if (result.CacheToMemory) { CacheItemPriority normal; BuildResultCompiledAssemblyBase base2 = result as BuildResultCompiledAssemblyBase; if (((base2 != null) && (base2.ResultAssembly != null)) && !base2.UsesExistingAssembly) { string assemblyCacheKey = BuildResultCache.GetAssemblyCacheKey(base2.ResultAssembly); Assembly assembly = (Assembly) this._cache.Get(assemblyCacheKey); if (assembly == null) { this._cache.UtcInsert(assemblyCacheKey, base2.ResultAssembly, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null); } CacheDependency dependency2 = new CacheDependency(0, null, new string[] { assemblyCacheKey }); if (dependencies != null) { AggregateCacheDependency dependency3 = new AggregateCacheDependency(); dependency3.Add(new CacheDependency[] { dependencies, dependency2 }); dependencies = dependency3; } else { dependencies = dependency2; } } string memoryCacheKey = GetMemoryCacheKey(cacheKey); if (result.IsUnloadable) { normal = CacheItemPriority.Normal; } else { normal = CacheItemPriority.NotRemovable; } CacheItemRemovedCallback onRemoveCallback = null; if (result.ShutdownAppDomainOnChange || (result is BuildResultCompiledAssemblyBase)) { if (this._onRemoveCallback == null) { this._onRemoveCallback = new CacheItemRemovedCallback(this.OnCacheItemRemoved); } onRemoveCallback = this._onRemoveCallback; } this._cache.UtcInsert(memoryCacheKey, result, dependencies, result.MemoryCacheExpiration, result.MemoryCacheSlidingExpiration, normal, onRemoveCallback); } } }
internal void SaveBuildResultToFile(string preservationFile, BuildResult result, long hashCode) { this._writer = new XmlTextWriter(preservationFile, Encoding.UTF8); try { this._writer.Formatting = Formatting.Indented; this._writer.Indentation = 4; this._writer.WriteStartDocument(); this._writer.WriteStartElement("preserve"); this.SetAttribute("resultType", ((int) result.GetCode()).ToString(CultureInfo.InvariantCulture)); if (result.VirtualPath != null) { this.SetAttribute("virtualPath", result.VirtualPath.VirtualPathString); } this.SetAttribute("hash", result.ComputeHashCode(hashCode).ToString("x", CultureInfo.InvariantCulture)); string virtualPathDependenciesHash = result.VirtualPathDependenciesHash; if (virtualPathDependenciesHash != null) { this.SetAttribute("filehash", virtualPathDependenciesHash); } result.SetPreservedAttributes(this); this.SaveDependencies(result.VirtualPathDependencies); this._writer.WriteEndElement(); this._writer.WriteEndDocument(); this._writer.Close(); } catch { this._writer.Close(); File.Delete(preservationFile); throw; } }
internal void SaveBuildResultToFile(string preservationFile, BuildResult result, long hashCode) { _writer = new XmlTextWriter(preservationFile, Encoding.UTF8); try { _writer.Formatting = Formatting.Indented; _writer.Indentation = 4; _writer.WriteStartDocument(); // <preserve assem="assemblyFile"> _writer.WriteStartElement("preserve"); // Save the type of BuildResult we're dealing with Debug.Assert(result.GetCode() != BuildResultTypeCode.Invalid); SetAttribute("resultType", ((int)result.GetCode()).ToString(CultureInfo.InvariantCulture)); // Save the virtual path for this BuildResult if (result.VirtualPath != null) SetAttribute("virtualPath", result.VirtualPath.VirtualPathString); // Get the hash code of the BuildResult long hash = result.ComputeHashCode(hashCode); // The hash should always be valid if we got here. Debug.Assert(hash != 0, "hash != 0"); // Save it to the preservation file SetAttribute("hash", hash.ToString("x", CultureInfo.InvariantCulture)); // Can be null if that's what the VirtualPathProvider returns string fileHash = result.VirtualPathDependenciesHash; if (fileHash != null) SetAttribute("filehash", fileHash); result.SetPreservedAttributes(this); SaveDependencies(result.VirtualPathDependencies); // </preserve> _writer.WriteEndElement(); _writer.WriteEndDocument(); _writer.Close(); } catch { // If an exception occurs during the writing of the xml file, clean it up _writer.Close(); File.Delete(preservationFile); throw; } }
internal override void CacheBuildResult(string cacheKey, BuildResult result, long hashCode, DateTime utcStart) { if (result.CacheToDisk) { if (HostingEnvironment.ShutdownInitiated) { BuildResultCompiledAssemblyBase base2 = result as BuildResultCompiledAssemblyBase; if (base2 != null) { this.MarkAssemblyAndRelatedFilesForDeletion(base2.ResultAssembly.GetName().Name); } } else { string preservedDataFileName = this.GetPreservedDataFileName(cacheKey); new PreservationFileWriter(this.PrecompilationMode).SaveBuildResultToFile(preservedDataFileName, result, hashCode); } } }
internal BuildDependencySet(BuildResult result) { _result = result; }
internal override void CacheBuildResult(string cacheKey, BuildResult result, long hashCode, DateTime utcStart) { // Nothing to cache to disk if the app is already precompiled }
static internal bool UsesDelayLoadType(BuildResult result) { BuildResultCompiledType buildResultCompiledType = result as BuildResultCompiledType; if (buildResultCompiledType != null) { return buildResultCompiledType.IsDelayLoadType; } else { return false; } }
internal override void CacheBuildResult(string cacheKey, BuildResult result, long hashCode, DateTime utcStart) { ICollection virtualDependencies = result.VirtualPathDependencies; Debug.Trace("BuildResultCache", "Adding cache " + cacheKey + " in the memory cache"); CacheDependency cacheDependency = null; if (virtualDependencies != null) { cacheDependency = result.VirtualPath.GetCacheDependency(virtualDependencies, utcStart); // If we got a cache dependency, remember that in the BuildResult if (cacheDependency != null) { result.UsesCacheDependency = true; } } // If it should not be cached to memory, leave it alone if (!result.CacheToMemory) { return; } if (BuildResultCompiledType.UsesDelayLoadType(result)) { // If the result is delaying loading of assembly, then don't cache // to avoid having to load the assembly. return; } BuildResultCompiledAssemblyBase compiledResult = result as BuildResultCompiledAssemblyBase; if (compiledResult != null && compiledResult.ResultAssembly != null && !compiledResult.UsesExistingAssembly) { // Insert a new cache entry using the assembly path as the key string assemblyKey = GetAssemblyCacheKey(compiledResult.ResultAssembly); Assembly a = (Assembly)HttpRuntime.Cache.InternalCache.Get(assemblyKey); if (a == null) { Debug.Trace("BuildResultCache", "Adding marker cache entry " + compiledResult.ResultAssembly); // VSWhidbey 500049 - add as NotRemovable to prevent the assembly from being prematurely deleted HttpRuntime.Cache.InternalCache.Insert(assemblyKey, compiledResult.ResultAssembly, null); } else { Debug.Assert(a == compiledResult.ResultAssembly); } // Now create a dependency based on that key. This way, by removing that key, we are able to // remove all the pages that live in that assembly from the cache. CacheDependency assemblyCacheDependency = new CacheDependency(0, null, new string[] { assemblyKey }); if (cacheDependency != null) { // We can't share the same CacheDependency, since we don't want the UtcStart // behavior for the assembly. Use an Aggregate to put the two together. AggregateCacheDependency tmpDependency = new AggregateCacheDependency(); tmpDependency.Add(new CacheDependency[] { cacheDependency, assemblyCacheDependency }); cacheDependency = tmpDependency; } else { cacheDependency = assemblyCacheDependency; } } string key = GetMemoryCacheKey(cacheKey); // Only allow the cache item to expire if the result can be unloaded. Otherwise, // we may as well cache it forever (e.g. for Assemblies and Types). CacheItemPriority cachePriority; if (result.IsUnloadable) { cachePriority = CacheItemPriority.Default; } else { cachePriority = CacheItemPriority.NotRemovable; } CacheItemRemovedCallback onRemoveCallback = null; // If the appdomain needs to be shut down when the item becomes invalid, register // a callback to do the shutdown. if (result.ShutdownAppDomainOnChange || result is BuildResultCompiledAssemblyBase) { // Create the delegate on demand if (_onRemoveCallback == null) { _onRemoveCallback = new CacheItemRemovedCallback(OnCacheItemRemoved); } onRemoveCallback = _onRemoveCallback; } HttpRuntime.Cache.InternalCache.Insert(key, result, new CacheInsertOptions() { Dependencies = cacheDependency, AbsoluteExpiration = result.MemoryCacheExpiration, SlidingExpiration = result.MemoryCacheSlidingExpiration, Priority = cachePriority, OnRemovedCallback = onRemoveCallback }); }
internal abstract void CacheBuildResult(string cacheKey, BuildResult result, long hashCode, DateTime utcStart);
internal void CacheBuildResult(string cacheKey, BuildResult result, DateTime utcStart) { CacheBuildResult(cacheKey, result, 0 /*hashCode*/, utcStart); }
internal void SetBuildResultDependencies(BuildResult result) { result.AddVirtualPathDependencies(this.VirtualPathDependencies); }
internal static bool UsesDelayLoadType(BuildResult result) { BuildResultCompiledType type = result as BuildResultCompiledType; return ((type != null) && type.IsDelayLoadType); }
internal BuildDependencySet(BuildResult result) { this._result = result; }
private BuildResult ReadFileInternal(VirtualPath virtualPath, string preservationFile, long hashCode, bool ensureIsUpToDate) { XmlDocument doc = new XmlDocument(); doc.Load(preservationFile); // Get the root element, and make sure it's what we expect _root = doc.DocumentElement; Debug.Assert(_root != null && _root.Name == "preserve", "_root != null && _root.Name == \"preserve\""); if (_root == null || _root.Name != "preserve") { return(null); } // Get the type of the BuildResult preserved in this file string resultTypeCodeString = GetAttribute("resultType"); BuildResultTypeCode resultTypeCode = (BuildResultTypeCode)Int32.Parse( resultTypeCodeString, CultureInfo.InvariantCulture); // Get the config path that affects this BuildResult if one wasn't passed in. // Note that the passed in path may be different with Sharepoint-like ghosting (VSWhidbey 343230) if (virtualPath == null) { virtualPath = VirtualPath.Create(GetAttribute("virtualPath")); } long savedHash = 0; string savedFileHash = null; // Ignore dependencies in precompilation mode if (!_precompilationMode) { // Read the saved hash from the preservation file string hashString = GetAttribute("hash"); Debug.Assert(hashString != null, "hashString != null"); if (hashString == null) { return(null); } // Parse the saved hash string as an hex int savedHash = Int64.Parse(hashString, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture); // Read the saved file hash from the preservation file. This is the hash the represents // the state of all the virtual files that the build result depends on. savedFileHash = GetAttribute("filehash"); } // Create the BuildResult accordingly BuildResult result = BuildResult.CreateBuildResultFromCode(resultTypeCode, virtualPath); // Ignore dependencies in precompilation mode if (!_precompilationMode) { ReadDependencies(); if (_sourceDependencies != null) { result.SetVirtualPathDependencies(_sourceDependencies); } result.VirtualPathDependenciesHash = savedFileHash; // Check if the build result is up to date bool outOfDate = false; if (!result.IsUpToDate(virtualPath, ensureIsUpToDate)) { Debug.Trace("PreservationFileReader", Path.GetFileName(preservationFile) + " is out of date (IsUpToDate==false)"); outOfDate = true; } else { // The virtual paths hash code was up to date, so check the // other hash code. // Get the current hash code long currentHash = result.ComputeHashCode(hashCode); // If the hash doesn't match, the preserved data is out of date if (currentHash == 0 || currentHash != savedHash) { outOfDate = true; Debug.Trace("PreservationFileReader", Path.GetFileName(preservationFile) + " is out of date (ComputeHashCode)"); } } if (outOfDate) { bool gotLock = false; try { // We need to delete the preservation file together with the assemblies/pdbs // under the same lock so to avoid bad interleaving where one process // deletes the .compiled file that another process just created, orphaning // the files generated by the other process. // (Dev10 CompilationLock.GetLock(ref gotLock); // Give the BuildResult a chance to do some cleanup result.RemoveOutOfDateResources(this); // The preservation file is not useable, so delete it File.Delete(preservationFile); } finally { // Always release the mutex if we had taken it if (gotLock) { CompilationLock.ReleaseLock(); } } return(null); } } // Ask the BuildResult to read the data it needs result.GetPreservedAttributes(this); return(result); }
private void AddBuildProviders(bool retryIfDeletionHappens) { DiskBuildResultCache.ResetAssemblyDeleted(); foreach (VirtualFile vfile in _vdir.Files) { // If it's already built and up to date, skip it BuildResult result = null; try { result = BuildManager.GetVPathBuildResultFromCache(vfile.VirtualPathObject); } catch { // Ignore the cached error in batch compilation mode, since we want to compile // as many files as possible. // But don't ignore it in CBM or precompile cases, since we always want to try // to compile everything that had failed before. if (!BuildManager.PerformingPrecompilation) { // Skip it if an exception occurs (e.g. if a compile error was cached for it) continue; } } if (result != null) { continue; } BuildProvider buildProvider = BuildManager.CreateBuildProvider(vfile.VirtualPathObject, _compConfig, _referencedAssemblies, false /*failIfUnknown*/); // Non-supported file type if (buildProvider == null) { continue; } // IgnoreFileBuildProvider's should never be created Debug.Assert(!(buildProvider is IgnoreFileBuildProvider)); _buildProviders[vfile.VirtualPath] = buildProvider; } // If an assembly had to be deleted/renamed as a result of calling GetVPathBuildResultFromCache, // me way need to run the AddBuildProviders logic again. The reason is that as a result of // deleting the assembly, we may have invalidated other BuildResult that we had earlier found // to be up to date (VSWhidbey 269297) if (DiskBuildResultCache.InUseAssemblyWasDeleted) { Debug.Assert(retryIfDeletionHappens); // Only retry if we're doing precompilation. For standard batching, we can live // with the fact that not everything will be built after we're done (and we want to // be done as quickly as possible since the user is waiting). if (retryIfDeletionHappens && BuildManager.PerformingPrecompilation) { Debug.Trace("WebDirectoryBatchCompiler", "Rerunning AddBuildProviders for '" + _vdir.VirtualPath + "' because an assembly was out of date."); // Pass false for retryIfDeletionHappens to make sure we don't get in an // infinite recursion. AddBuildProviders(false /*retryIfDeletionHappens*/); } } }
internal static bool UsesDelayLoadType(BuildResult result) { BuildResultCompiledType type = result as BuildResultCompiledType; return((type != null) && type.IsDelayLoadType); }
internal void CacheBuildResult(string cacheKey, BuildResult result, DateTime utcStart) { this.CacheBuildResult(cacheKey, result, 0L, utcStart); }
internal override void CacheBuildResult(string cacheKey, BuildResult result, long hashCode, DateTime utcStart) { }
internal override void CacheBuildResult(string cacheKey, BuildResult result, long hashCode, DateTime utcStart) { ICollection virtualDependencies = result.VirtualPathDependencies; Debug.Trace("BuildResultCache", "Adding cache " + cacheKey + " in the memory cache"); CacheDependency cacheDependency = null; if (virtualDependencies != null) { cacheDependency = result.VirtualPath.GetCacheDependency(virtualDependencies, utcStart); // If we got a cache dependency, remember that in the BuildResult if (cacheDependency != null) result.UsesCacheDependency = true; } // If it should not be cached to memory, leave it alone if (!result.CacheToMemory) { return; } if (BuildResultCompiledType.UsesDelayLoadType(result)) { // If the result is delaying loading of assembly, then don't cache // to avoid having to load the assembly. return; } BuildResultCompiledAssemblyBase compiledResult = result as BuildResultCompiledAssemblyBase; if (compiledResult != null && compiledResult.ResultAssembly != null && !compiledResult.UsesExistingAssembly) { // Insert a new cache entry using the assembly path as the key string assemblyKey = GetAssemblyCacheKey(compiledResult.ResultAssembly); Assembly a = (Assembly)_cache.Get(assemblyKey); if (a == null) { Debug.Trace("BuildResultCache", "Adding marker cache entry " + compiledResult.ResultAssembly); // VSWhidbey 500049 - add as NotRemovable to prevent the assembly from being prematurely deleted _cache.UtcInsert(assemblyKey, compiledResult.ResultAssembly, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null); } else { Debug.Assert(a == compiledResult.ResultAssembly); } // Now create a dependency based on that key. This way, by removing that key, we are able to // remove all the pages that live in that assembly from the cache. CacheDependency assemblyCacheDependency = new CacheDependency(0, null, new string[] { assemblyKey }); if (cacheDependency != null) { // We can't share the same CacheDependency, since we don't want the UtcStart // behavior for the assembly. Use an Aggregate to put the two together. AggregateCacheDependency tmpDependency = new AggregateCacheDependency(); tmpDependency.Add(new CacheDependency[] { cacheDependency, assemblyCacheDependency }); cacheDependency = tmpDependency; } else { cacheDependency = assemblyCacheDependency; } } string key = GetMemoryCacheKey(cacheKey); // Only allow the cache item to expire if the result can be unloaded. Otherwise, // we may as well cache it forever (e.g. for Assemblies and Types). CacheItemPriority cachePriority; if (result.IsUnloadable) cachePriority = CacheItemPriority.Default; else cachePriority = CacheItemPriority.NotRemovable; CacheItemRemovedCallback onRemoveCallback = null; // If the appdomain needs to be shut down when the item becomes invalid, register // a callback to do the shutdown. if (result.ShutdownAppDomainOnChange || result is BuildResultCompiledAssemblyBase) { // Create the delegate on demand if (_onRemoveCallback == null) _onRemoveCallback = new CacheItemRemovedCallback(OnCacheItemRemoved); onRemoveCallback = _onRemoveCallback; } _cache.UtcInsert(key, result, cacheDependency, result.MemoryCacheExpiration, result.MemoryCacheSlidingExpiration, cachePriority, onRemoveCallback); }
private BuildResult PostProcessFoundBuildResult(BuildResult result, bool keyFromVPP, VirtualPath virtualPath) { // Check that the virtual path in the result matches the passed in // virtualPath (VSWhidbey 516641). But skip this check in case the key came from // calling VirtualPathProvider.GetCacheKey, as it may legitimately not match. if (!keyFromVPP) { if (virtualPath != null && virtualPath != result.VirtualPath) { Debug.Assert(false); return null; } } // If what we found in the cache is a CompileError, rethrow the exception if (result is BuildResultCompileError) { // Report the cached error from Callback interface. HttpCompileException compileException = ((BuildResultCompileError)result).CompileException; // But don't report it if we're doing precompilation, as that would cause it to be // reported twice because we always try to compile everything that has failed // before (VSWhidbey 525414) if (!PerformingPrecompilation) { ReportErrorsFromException(compileException); } throw compileException; } return result; }
internal override void CacheBuildResult(string cacheKey, BuildResult result, long hashCode, DateTime utcStart) { // If it should not be cached to disk, leave it alone if (!result.CacheToDisk) return; // VSWhidbey 564168 don't save to disk if already shutting down, otherwise we might // be persisting assembly that was compiled with obsolete references. // Since we are shutting down and not creating any cache, delete the compiled result // as it will not be used in future. if (HostingEnvironment.ShutdownInitiated) { BuildResultCompiledAssemblyBase compiledResult = result as BuildResultCompiledAssemblyBase; if (compiledResult != null) MarkAssemblyAndRelatedFilesForDeletion(compiledResult.ResultAssembly.GetName().Name); return; } string preservationFile = GetPreservedDataFileName(cacheKey); PreservationFileWriter pfw = new PreservationFileWriter(PrecompilationMode); pfw.SaveBuildResultToFile(preservationFile, result, hashCode); }
private bool CacheVPathBuildResultInternal(VirtualPath virtualPath, BuildResult result, DateTime utcStart) { string cacheKey = GetCacheKeyFromVirtualPath(virtualPath); return CacheBuildResult(cacheKey, result, utcStart); }
internal override void CacheBuildResult(string cacheKey, BuildResult result, long hashCode, DateTime utcStart) { // Don't create preservation files in bin for pages in the updatable model, // because we turn them into a v1 style code behind, which works as a result of // having the aspx file point to the bin class via an inherits attribute. if (result is BuildResultCompiledTemplateType) return; base.CacheBuildResult(cacheKey, result, hashCode, utcStart); }
private bool CacheBuildResultInternal(string cacheKey, BuildResult result, long hashCode, DateTime utcStart) { // Before caching it, make sure the hash has been computed result.EnsureVirtualPathDependenciesHashComputed(); for (int i = 0; i < _caches.Length; i++) { _caches[i].CacheBuildResult(cacheKey, result, hashCode, utcStart); } // If we find that it's no longer valid after caching it, remove it from the cache (VSWhidbey 578372) if (!TimeStampChecker.CheckFilesStillValid(cacheKey, result.VirtualPathDependencies)) { _memoryCache.RemoveAssemblyAndCleanupDependencies(result as BuildResultCompiledAssemblyBase); return false; } return true; }
[global::Umbraco.Web.WebApi.UmbracoAuthorize] // can use Umbraco's public HttpResponseMessage BuildModels() { try { // the UmbracoAuthorize attribute validates the current user // the UmbracoAuthorizedApiController would in addition check for .Disabled and .NoConsole // but to do it it relies on internal methods so we have to do it here explicitely // was doing it using legacy User class, now using new API class //var user = umbraco.BusinessLogic.User.GetCurrent(); var user = UmbracoContext.Security.CurrentUser; //if (user.Disabled || user.NoConsole) if (!user.IsApproved && user.IsLockedOut) return new HttpResponseMessage(HttpStatusCode.Unauthorized); //if (user.Applications.All(x => x.alias != "developer")) if (!user.AllowedSections.Contains("developer")) return new HttpResponseMessage(HttpStatusCode.Unauthorized); if (!Config.EnableAppDataModels && !Config.EnableAppCodeModels && !Config.EnableDllModels) { var result2 = new BuildResult { Success = false, Message = "Models generation is not enabled." }; return Request.CreateResponse(HttpStatusCode.OK, result2, Configuration.Formatters.JsonFormatter); } var appData = HostingEnvironment.MapPath("~/App_Data"); if (appData == null) throw new Exception("Panic: appData is null."); var appCode = HostingEnvironment.MapPath("~/App_Code"); if (appCode == null) throw new Exception("Panic: appCode is null."); var bin = HostingEnvironment.MapPath("~/bin"); if (bin== null) throw new Exception("Panic: bin is null."); // EnableDllModels will recycle the app domain - but this request will end properly GenerateModels(appData, Config.EnableDllModels ? bin : null); // will recycle the app domain - but this request will end properly if (Config.EnableAppCodeModels) TouchModelsFile(appCode); var result = new BuildResult {Success = true}; return Request.CreateResponse(HttpStatusCode.OK, result, Configuration.Formatters.JsonFormatter); } catch (Exception e) { var message = string.Format("{0}: {1}\r\n{2}", e.GetType().FullName, e.Message, e.StackTrace); var result = new BuildResult { Success = false, Message = message }; return Request.CreateResponse(HttpStatusCode.OK, result, Configuration.Formatters.JsonFormatter); } }
internal static bool CacheVPathBuildResult(VirtualPath virtualPath, BuildResult result, DateTime utcStart) { return _theBuildManager.CacheVPathBuildResultInternal(virtualPath, result, utcStart); }
internal void SetBuildResultDependencies(BuildResult result) { result.AddVirtualPathDependencies(VirtualPathDependencies); }
internal static bool CacheBuildResult(string cacheKey, BuildResult result, DateTime utcStart) { return _theBuildManager.CacheBuildResultInternal(cacheKey, result, 0 /*hashCode*/, utcStart); }
/* * Add a BuildResult's source dependencies to our own source dependencies */ internal void AddBuildResultDependency(BuildResult result) { // Add one direct dependency if (_pageParserFilter != null) _pageParserFilter.OnDirectDependencyAdded(); if (result.VirtualPathDependencies == null) return; foreach (string virtualPath in result.VirtualPathDependencies) { // Add one dependency for each file (to include direct and indirect) if (_pageParserFilter != null) _pageParserFilter.OnDependencyAdded(); AddSourceDependency2(VirtualPath.Create(virtualPath)); } }
internal static Assembly GetCodeDirectoryAssembly(VirtualPath virtualDir, CodeDirectoryType dirType, string assemblyName, StringSet excludedSubdirectories, bool isDirectoryAllowed) { string physicalDir = virtualDir.MapPath(); if (!isDirectoryAllowed) { // The directory should never exist in a precompiled app if (Directory.Exists(physicalDir)) { throw new HttpException(SR.GetString(SR.Bar_dir_in_precompiled_app, virtualDir)); } } bool supportLocalization = IsResourceCodeDirectoryType(dirType); // Determine the proper cache key based on the type of directory we're processing string cacheKey = assemblyName; // Try the cache first BuildResult result = BuildManager.GetBuildResultFromCache(cacheKey); Assembly resultAssembly = null; // If it's cached, just return it if (result != null) { // It should always be a BuildResultCompiledAssembly, though if there is // a VirtualPathProvider doing very bad things, it may not (VSWhidbey 341701) Debug.Assert(result is BuildResultCompiledAssembly); if (result is BuildResultCompiledAssembly) { // If it's the main code assembly, keep track of it so we can later call // the AppInitialize method if (result is BuildResultMainCodeAssembly) { Debug.Assert(dirType == CodeDirectoryType.MainCode); Debug.Assert(_mainCodeBuildResult == null); _mainCodeBuildResult = (BuildResultMainCodeAssembly)result; } resultAssembly = ((BuildResultCompiledAssembly)result).ResultAssembly; if (!supportLocalization) { return(resultAssembly); } // We found a preserved resource assembly. However, we may not be done, // as the culture specific files may have changed. // But don't make any further checks if the directory is not allowed (precomp secenario). // In that case, we should always return the assembly (VSWhidbey 533498) if (!isDirectoryAllowed) { return(resultAssembly); } BuildResultResourceAssembly buildResultResAssembly = (BuildResultResourceAssembly)result; string newResourcesDependenciesHash = HashCodeCombiner.GetDirectoryHash(virtualDir); // If the resources hash (which includes satellites) is up to date, we're done if (newResourcesDependenciesHash == buildResultResAssembly.ResourcesDependenciesHash) { return(resultAssembly); } } } // If app was precompiled, don't attempt compilation if (!isDirectoryAllowed) { return(null); } // Check whether the virtual dir is mapped to a different application, // which we don't support (VSWhidbey 218603). But don't do this for LocalResource (VSWhidbey 237935) if (dirType != CodeDirectoryType.LocalResources && !StringUtil.StringStartsWithIgnoreCase(physicalDir, HttpRuntime.AppDomainAppPathInternal)) { throw new HttpException(SR.GetString(SR.Virtual_codedir, virtualDir.VirtualPathString)); } // If the directory doesn't exist, we may be done if (!Directory.Exists(physicalDir)) { // We're definitely done if it's not the main code dir if (dirType != CodeDirectoryType.MainCode) { return(null); } // If it is the main code dir, we're only done is there is no profile to compile // since the profice gets built as part of the main assembly. if (!ProfileBuildProvider.HasCompilableProfile) { return(null); } } // Otherwise, compile it BuildManager.ReportDirectoryCompilationProgress(virtualDir); DateTime utcStart = DateTime.UtcNow; CodeDirectoryCompiler cdc = new CodeDirectoryCompiler(virtualDir, dirType, excludedSubdirectories); string outputAssemblyName = null; if (resultAssembly != null) { // If resultAssembly is not null, we are in the case where we just need to build // the localized resx file in a resources dir (local or global) Debug.Assert(supportLocalization); outputAssemblyName = resultAssembly.GetName().Name; cdc._onlyBuildLocalizedResources = true; } else { outputAssemblyName = BuildManager.GenerateRandomAssemblyName(assemblyName); } BuildProvidersCompiler bpc = new BuildProvidersCompiler(virtualDir, supportLocalization, outputAssemblyName); cdc._bpc = bpc; // Find all the build provider we want to compile from the code directory cdc.FindBuildProviders(); // Give them to the BuildProvidersCompiler bpc.SetBuildProviders(cdc._buildProviders); // Compile them into an assembly CompilerResults results = bpc.PerformBuild(); // Did we just compile something? if (results != null) { Debug.Assert(result == null); Debug.Assert(resultAssembly == null); // If there is already a loaded module with the same path, try to wait for it to be unloaded. // Otherwise, we would end up loading this old assembly instead of the new one (VSWhidbey 554697) DateTime waitLimit = DateTime.UtcNow.AddMilliseconds(3000); for (;;) { IntPtr hModule = UnsafeNativeMethods.GetModuleHandle(results.PathToAssembly); if (hModule == IntPtr.Zero) { break; } Debug.Trace("CodeDirectoryCompiler", results.PathToAssembly + " is already loaded. Waiting a bit"); System.Threading.Thread.Sleep(250); // Stop trying if the timeout was reached if (DateTime.UtcNow > waitLimit) { Debug.Trace("CodeDirectoryCompiler", "Timeout waiting for old assembly to unload: " + results.PathToAssembly); throw new HttpException(SR.GetString(SR.Assembly_already_loaded, results.PathToAssembly)); } } resultAssembly = results.CompiledAssembly; } // It is possible that there was nothing to compile (and we're not in the // satellite resources case) if (resultAssembly == null) { return(null); } // For the main code directory, use a special BuildResult that takes care of // calling AppInitialize if it finds one if (dirType == CodeDirectoryType.MainCode) { // Keep track of it so we can later call the AppInitialize method _mainCodeBuildResult = new BuildResultMainCodeAssembly(resultAssembly); result = _mainCodeBuildResult; } else if (supportLocalization) { result = new BuildResultResourceAssembly(resultAssembly); } else { result = new BuildResultCompiledAssembly(resultAssembly); } result.VirtualPath = virtualDir; // If compilations are optimized, we need to include the right dependencies, since we can no longer // rely on everything getting wiped out when something in App_Code changes. // But don't do this for local resources, since they have their own special way of // dealing with dependencies (in BuildResultResourceAssembly.ComputeSourceDependenciesHashCode). // It's crucial *not* to do it as it triggers a tricky infinite recursion due to the fact // that GetBuildResultFromCacheInternal calls EnsureFirstTimeDirectoryInitForDependencies if // there is at least one dependency if (BuildManager.OptimizeCompilations && dirType != CodeDirectoryType.LocalResources) { result.AddVirtualPathDependencies(new SingleObjectCollection(virtualDir.AppRelativeVirtualPathString)); } // Top level assembly should not be cached to memory. But LocalResources are *not* // top level files, and do benefit from memory caching if (dirType != CodeDirectoryType.LocalResources) { result.CacheToMemory = false; } // Cache it for next time BuildManager.CacheBuildResult(cacheKey, result, utcStart); return(resultAssembly); }