static void GenerateAssembly (AssemblyBuilder abuilder, BuildProviderGroup group, VirtualPath vp, bool debug) { IDictionary <string, bool> deps; BuildManagerCacheItem bmci; string bvp, vpabsolute = vp.Absolute; StringBuilder sb; string newline; int failedCount = 0; if (debug) { newline = Environment.NewLine; sb = new StringBuilder ("Code generation for certain virtual paths in a batch failed. Those files have been removed from the batch." + newline); sb.Append ("Since you're running in debug mode, here's some more information about the error:" + newline); } else { newline = null; sb = null; } List <BuildProvider> failedBuildProviders = null; StringComparison stringComparison = RuntimeHelpers.StringComparison; foreach (BuildProvider bp in group) { bvp = bp.VirtualPath; if (HasCachedItemNoLock (bvp)) continue; try { bp.GenerateCode (abuilder); } catch (Exception ex) { if (String.Compare (bvp, vpabsolute, stringComparison) == 0) { if (ex is CompilationException || ex is ParseException) throw; throw new HttpException ("Code generation failed.", ex); } if (failedBuildProviders == null) failedBuildProviders = new List <BuildProvider> (); failedBuildProviders.Add (bp); failedCount++; if (sb != null) { if (failedCount > 1) sb.Append (newline); sb.AppendFormat ("Failed file virtual path: {0}; Exception: {1}{2}{1}", bp.VirtualPath, newline, ex); } continue; } deps = bp.ExtractDependencies (); if (deps != null) { foreach (var dep in deps) { bmci = GetCachedItemNoLock (dep.Key); if (bmci == null || bmci.BuiltAssembly == null) continue; abuilder.AddAssemblyReference (bmci.BuiltAssembly); } } } if (sb != null && failedCount > 0) ShowDebugModeMessage (sb.ToString ()); if (failedBuildProviders != null) { foreach (BuildProvider bp in failedBuildProviders) group.Remove (bp); } foreach (Assembly asm in referencedAssemblies) { if (asm == null) continue; abuilder.AddAssemblyReference (asm); } CompilerResults results = abuilder.BuildAssembly (vp); // No results is not an error - it is possible that the assembly builder contained only .asmx and // .ashx files which had no body, just the directive. In such case, no code unit or code file is added // to the assembly builder and, in effect, no assembly is produced but there are STILL types that need // to be added to the cache. Assembly compiledAssembly = results != null ? results.CompiledAssembly : null; try { buildCacheLock.EnterWriteLock (); if (compiledAssembly != null) referencedAssemblies.Add (compiledAssembly); foreach (BuildProvider bp in group) { if (HasCachedItemNoLock (bp.VirtualPath)) continue; StoreInCache (bp, compiledAssembly, results); } } finally { buildCacheLock.ExitWriteLock (); } }
static void RemoveFailedAssemblies (string requestedVirtualPath, CompilationException ex, AssemblyBuilder abuilder, BuildProviderGroup group, CompilerResults results, bool debug) { StringBuilder sb; string newline; if (debug) { newline = Environment.NewLine; sb = new StringBuilder ("Compilation of certain files in a batch failed. Another attempt to compile the batch will be made." + newline); sb.Append ("Since you're running in debug mode, here's some more information about the error:" + newline); } else { newline = null; sb = null; } var failedBuildProviders = new List <BuildProvider> (); BuildProvider bp; HttpContext ctx = HttpContext.Current; HttpRequest req = ctx != null ? ctx.Request : null; bool rethrow = false; foreach (CompilerError error in results.Errors) { if (error.IsWarning) continue; bp = abuilder.GetBuildProviderForPhysicalFilePath (error.FileName); if (bp == null) { bp = FindBuildProviderForPhysicalPath (error.FileName, group, req); if (bp == null) continue; } if (String.Compare (bp.VirtualPath, requestedVirtualPath, StringComparison.Ordinal) == 0) rethrow = true; if (!failedBuildProviders.Contains (bp)) { failedBuildProviders.Add (bp); if (sb != null) sb.AppendFormat ("\t{0}{1}", bp.VirtualPath, newline); } if (sb != null) sb.AppendFormat ("\t\t{0}{1}", error, newline); } foreach (BuildProvider fbp in failedBuildProviders) group.Remove (fbp); if (sb != null) { sb.AppendFormat ("{0}The following exception has been thrown for the file(s) listed above:{0}{1}", newline, ex.ToString ()); ShowDebugModeMessage (sb.ToString ()); sb = null; } if (rethrow) throw new HttpException ("Compilation failed.", ex); }
static BuildProvider FindBuildProviderForPhysicalPath (string path, BuildProviderGroup group, HttpRequest req) { if (req == null || String.IsNullOrEmpty (path)) return null; foreach (BuildProvider bp in group) { if (String.Compare (path, req.MapPath (bp.VirtualPath), RuntimeHelpers.StringComparison) == 0) return bp; } return null; }
static bool SkipApplicationGroup (BuildProviderGroup group) { if (group == null) return false; return group.Application; }
static bool SkipStandaloneGroups (BuildProviderGroup group) { if (group == null) return false; return group.Standalone; }
void InsertGroup (BuildProviderGroup group, List <BuildProviderGroup> groups) { if (group.Application) { groups.Insert (groups.Count - 1, group); return; } int index; if (group.Standalone) index = groups.FindLastIndex (SkipApplicationGroup); else index = groups.FindLastIndex (SkipStandaloneGroups); if (index == -1) groups.Add (group); else groups.Insert (index == 0 ? 0 : index - 1, group); }
void AssignToGroup (BuildProvider buildProvider, List <BuildProviderGroup> groups) { if (IsDependencyCycle (buildProvider)) throw new HttpException ("Dependency cycles are not suppported: " + buildProvider.VirtualPath); BuildProviderGroup myGroup = null; string bpVirtualPath = buildProvider.VirtualPath; string bpPath = VirtualPathUtility.GetDirectory (bpVirtualPath); bool canAdd; if (BuildManager.HasCachedItemNoLock (buildProvider.VirtualPath)) return; if (buildProvider is ApplicationFileBuildProvider || buildProvider is ThemeDirectoryBuildProvider) { // global.asax and theme directory go into their own assemblies myGroup = new BuildProviderGroup (); myGroup.Standalone = true; InsertGroup (myGroup, groups); } else { Type bpCodeDomType = GetBuildProviderCodeDomType (buildProvider); foreach (BuildProviderGroup group in groups) { if (group.Standalone) continue; if (group.Count == 0) { myGroup = group; break; } canAdd = true; foreach (BuildProvider bp in group) { if (IsDependency (buildProvider, bp)) { canAdd = false; break; } // There should be one assembly per virtual dir if (String.Compare (bpPath, VirtualPathUtility.GetDirectory (bp.VirtualPath), stringComparer) != 0) { canAdd = false; break; } // Different languages go to different assemblies if (bpCodeDomType != null) { Type type = GetBuildProviderCodeDomType (bp); if (type != null) { if (type != bpCodeDomType) { canAdd = false; break; } } } } if (!canAdd) continue; myGroup = group; break; } if (myGroup == null) { myGroup = new BuildProviderGroup (); InsertGroup (myGroup, groups); } } myGroup.AddProvider (buildProvider); if (String.Compare (bpPath, virtualPathDirectory, stringComparer) == 0) myGroup.Master = true; }
List <BuildProviderGroup> GetSingleBuildProviderGroup (BuildProvider bp) { var ret = new List <BuildProviderGroup> (); var group = new BuildProviderGroup (); group.AddProvider (bp); ret.Add (group); return ret; }