BuildManager.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479
  1. //
  2. // System.Web.Compilation.BuildManager
  3. //
  4. // Authors:
  5. // Chris Toshok ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. // Marek Habersack ([email protected])
  8. //
  9. // (C) 2006-2009 Novell, Inc (http://www.novell.com)
  10. //
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System;
  32. using System.CodeDom;
  33. using System.CodeDom.Compiler;
  34. using System.Collections;
  35. using System.Collections.Generic;
  36. using System.Collections.Specialized;
  37. using System.ComponentModel;
  38. using System.IO;
  39. using System.Reflection;
  40. using System.Text;
  41. using System.Threading;
  42. using System.Xml;
  43. using System.Web;
  44. using System.Web.Caching;
  45. using System.Web.Configuration;
  46. using System.Web.Hosting;
  47. using System.Web.Util;
  48. #if NET_4_0
  49. using System.Runtime.Versioning;
  50. #endif
  51. namespace System.Web.Compilation
  52. {
  53. public sealed class BuildManager
  54. {
  55. internal const string FAKE_VIRTUAL_PATH_PREFIX = "/@@MonoFakeVirtualPath@@";
  56. const string BUILD_MANAGER_VIRTUAL_PATH_CACHE_PREFIX = "@@Build_Manager@@";
  57. static int BUILD_MANAGER_VIRTUAL_PATH_CACHE_PREFIX_LENGTH = BUILD_MANAGER_VIRTUAL_PATH_CACHE_PREFIX.Length;
  58. static readonly object bigCompilationLock = new object ();
  59. static readonly object virtualPathsToIgnoreLock = new object ();
  60. static readonly char[] virtualPathsToIgnoreSplitChars = {','};
  61. static EventHandlerList events = new EventHandlerList ();
  62. static object buildManagerRemoveEntryEvent = new object ();
  63. static bool hosted;
  64. static Dictionary <string, bool> virtualPathsToIgnore;
  65. static bool virtualPathsToIgnoreChecked;
  66. static bool haveVirtualPathsToIgnore;
  67. static List <Assembly> AppCode_Assemblies = new List<Assembly>();
  68. static List <Assembly> TopLevel_Assemblies = new List<Assembly>();
  69. static Dictionary <Type, CodeDomProvider> codeDomProviders;
  70. static Dictionary <string, BuildManagerCacheItem> buildCache;
  71. static List <Assembly> referencedAssemblies;
  72. static List <Assembly> configReferencedAssemblies;
  73. static bool getReferencedAssembliesInvoked;
  74. static int buildCount;
  75. static bool is_precompiled;
  76. static bool allowReferencedAssembliesCaching;
  77. #if NET_4_0
  78. static List <Assembly> dynamicallyRegisteredAssemblies;
  79. static bool? batchCompilationEnabled;
  80. static FrameworkName targetFramework;
  81. static bool preStartMethodsDone;
  82. static bool preStartMethodsRunning;
  83. #endif
  84. //static bool updatable; unused
  85. static Dictionary<string, PreCompilationData> precompiled;
  86. // This is here _only_ for the purpose of unit tests!
  87. internal static bool suppressDebugModeMessages;
  88. // See comment for the cacheLock field at top of System.Web.Caching/Cache.cs
  89. #if SYSTEMCORE_DEP
  90. static ReaderWriterLockSlim buildCacheLock;
  91. #else
  92. static ReaderWriterLock buildCacheLock;
  93. #endif
  94. static ulong recursionDepth;
  95. internal static bool AllowReferencedAssembliesCaching {
  96. get { return allowReferencedAssembliesCaching; }
  97. set { allowReferencedAssembliesCaching = value; }
  98. }
  99. internal static bool IsPrecompiled {
  100. get { return is_precompiled; }
  101. }
  102. internal static event BuildManagerRemoveEntryEventHandler RemoveEntry {
  103. add { events.AddHandler (buildManagerRemoveEntryEvent, value); }
  104. remove { events.RemoveHandler (buildManagerRemoveEntryEvent, value); }
  105. }
  106. #if NET_4_0
  107. internal static bool CompilingTopLevelAssemblies {
  108. get; set;
  109. }
  110. internal static bool PreStartMethodsRunning {
  111. get { return preStartMethodsRunning; }
  112. }
  113. public static bool? BatchCompilationEnabled {
  114. get { return batchCompilationEnabled; }
  115. set {
  116. if (preStartMethodsDone)
  117. throw new InvalidOperationException ("This method cannot be called after the application's pre-start initialization stage.");
  118. batchCompilationEnabled = value;
  119. }
  120. }
  121. public static FrameworkName TargetFramework {
  122. get {
  123. if (targetFramework == null) {
  124. CompilationSection cs = CompilationConfig;
  125. string framework;
  126. if (cs == null)
  127. framework = null;
  128. else
  129. framework = cs.TargetFramework;
  130. if (String.IsNullOrEmpty (framework))
  131. targetFramework = new FrameworkName (".NETFramework,Version=v4.0");
  132. else
  133. targetFramework = new FrameworkName (framework);
  134. }
  135. return targetFramework;
  136. }
  137. }
  138. #endif
  139. internal static bool BatchMode {
  140. get {
  141. #if NET_4_0
  142. if (batchCompilationEnabled != null)
  143. return (bool)batchCompilationEnabled;
  144. #endif
  145. if (!hosted)
  146. return false; // Fix for bug #380985
  147. CompilationSection cs = CompilationConfig;
  148. if (cs == null)
  149. return true;
  150. return cs.Batch;
  151. }
  152. }
  153. // Assemblies built from the App_Code directory
  154. public static IList CodeAssemblies {
  155. get { return AppCode_Assemblies; }
  156. }
  157. internal static CompilationSection CompilationConfig {
  158. get { return WebConfigurationManager.GetWebApplicationSection ("system.web/compilation") as CompilationSection; }
  159. }
  160. internal static bool HaveResources {
  161. get; set;
  162. }
  163. internal static IList TopLevelAssemblies {
  164. get { return TopLevel_Assemblies; }
  165. }
  166. static BuildManager ()
  167. {
  168. hosted = (AppDomain.CurrentDomain.GetData (ApplicationHost.MonoHostedDataKey) as string) == "yes";
  169. buildCache = new Dictionary <string, BuildManagerCacheItem> (RuntimeHelpers.StringEqualityComparer);
  170. #if SYSTEMCORE_DEP
  171. buildCacheLock = new ReaderWriterLockSlim ();
  172. #else
  173. buildCacheLock = new ReaderWriterLock ();
  174. #endif
  175. referencedAssemblies = new List <Assembly> ();
  176. recursionDepth = 0;
  177. string appPath = HttpRuntime.AppDomainAppPath;
  178. string precomp_name = null;
  179. is_precompiled = String.IsNullOrEmpty (appPath) ? false : File.Exists ((precomp_name = Path.Combine (appPath, "PrecompiledApp.config")));
  180. if (is_precompiled)
  181. is_precompiled = LoadPrecompilationInfo (precomp_name);
  182. }
  183. #if NET_4_0
  184. internal static void AssertPreStartMethodsRunning ()
  185. {
  186. if (!BuildManager.PreStartMethodsRunning)
  187. throw new InvalidOperationException ("This method must be called during the application's pre-start initialization stage.");
  188. }
  189. #endif
  190. // Deal with precompiled sites deployed in a different virtual path
  191. static void FixVirtualPaths ()
  192. {
  193. if (precompiled == null)
  194. return;
  195. string [] parts;
  196. int skip = -1;
  197. foreach (string vpath in precompiled.Keys) {
  198. parts = vpath.Split ('/');
  199. for (int i = 0; i < parts.Length; i++) {
  200. if (String.IsNullOrEmpty (parts [i]))
  201. continue;
  202. // The path must be rooted, otherwise PhysicalPath returned
  203. // below will be relative to the current request path and
  204. // File.Exists will return a false negative. See bug #546053
  205. string test_path = "/" + String.Join ("/", parts, i, parts.Length - i);
  206. VirtualPath result = GetAbsoluteVirtualPath (test_path);
  207. if (result != null && File.Exists (result.PhysicalPath)) {
  208. skip = i - 1;
  209. break;
  210. }
  211. }
  212. }
  213. string app_vpath = HttpRuntime.AppDomainAppVirtualPath;
  214. if (skip == -1 || (skip == 0 && app_vpath == "/"))
  215. return;
  216. if (!app_vpath.EndsWith ("/"))
  217. app_vpath = app_vpath + "/";
  218. Dictionary<string, PreCompilationData> copy = new Dictionary<string, PreCompilationData> (precompiled);
  219. precompiled.Clear ();
  220. foreach (KeyValuePair<string,PreCompilationData> entry in copy) {
  221. parts = entry.Key.Split ('/');
  222. string new_path;
  223. if (String.IsNullOrEmpty (parts [0]))
  224. new_path = app_vpath + String.Join ("/", parts, skip + 1, parts.Length - skip - 1);
  225. else
  226. new_path = app_vpath + String.Join ("/", parts, skip, parts.Length - skip);
  227. entry.Value.VirtualPath = new_path;
  228. precompiled.Add (new_path, entry.Value);
  229. }
  230. }
  231. static bool LoadPrecompilationInfo (string precomp_config)
  232. {
  233. using (XmlTextReader reader = new XmlTextReader (precomp_config)) {
  234. reader.MoveToContent ();
  235. if (reader.Name != "precompiledApp")
  236. return false;
  237. /* unused
  238. if (reader.HasAttributes)
  239. while (reader.MoveToNextAttribute ())
  240. if (reader.Name == "updatable") {
  241. updatable = (reader.Value == "true");
  242. break;
  243. }
  244. */
  245. }
  246. string [] compiled = Directory.GetFiles (HttpRuntime.BinDirectory, "*.compiled");
  247. foreach (string str in compiled)
  248. LoadCompiled (str);
  249. FixVirtualPaths ();
  250. return true;
  251. }
  252. static void LoadCompiled (string filename)
  253. {
  254. using (XmlTextReader reader = new XmlTextReader (filename)) {
  255. reader.MoveToContent ();
  256. if (reader.Name == "preserve" && reader.HasAttributes) {
  257. reader.MoveToNextAttribute ();
  258. string val = reader.Value;
  259. // 1 -> app_code subfolder - add the assembly to CodeAssemblies
  260. // 2 -> ashx
  261. // 3 -> ascx, aspx
  262. // 6 -> app_code - add the assembly to CodeAssemblies
  263. // 8 -> global.asax
  264. // 9 -> App_GlobalResources - set the assembly for HttpContext
  265. if (reader.Name == "resultType" && (val == "2" || val == "3" || val == "8"))
  266. LoadPageData (reader, true);
  267. else if (val == "1" || val == "6") {
  268. PreCompilationData pd = LoadPageData (reader, false);
  269. CodeAssemblies.Add (Assembly.Load (pd.AssemblyFileName));
  270. } else if (val == "9") {
  271. PreCompilationData pd = LoadPageData (reader, false);
  272. HttpContext.AppGlobalResourcesAssembly = Assembly.Load (pd.AssemblyFileName);
  273. }
  274. }
  275. }
  276. }
  277. class PreCompilationData {
  278. public string VirtualPath;
  279. public string AssemblyFileName;
  280. public string TypeName;
  281. public Type Type;
  282. }
  283. static PreCompilationData LoadPageData (XmlTextReader reader, bool store)
  284. {
  285. PreCompilationData pc_data = new PreCompilationData ();
  286. while (reader.MoveToNextAttribute ()) {
  287. string name = reader.Name;
  288. if (name == "virtualPath")
  289. pc_data.VirtualPath = VirtualPathUtility.RemoveTrailingSlash (reader.Value);
  290. else if (name == "assembly")
  291. pc_data.AssemblyFileName = reader.Value;
  292. else if (name == "type")
  293. pc_data.TypeName = reader.Value;
  294. }
  295. if (store) {
  296. if (precompiled == null)
  297. precompiled = new Dictionary<string, PreCompilationData> (RuntimeHelpers.StringEqualityComparerCulture);
  298. precompiled.Add (pc_data.VirtualPath, pc_data);
  299. }
  300. return pc_data;
  301. }
  302. static void AddAssembly (Assembly asm, List <Assembly> al)
  303. {
  304. if (al.Contains (asm))
  305. return;
  306. al.Add (asm);
  307. }
  308. static void AddPathToIgnore (string vp)
  309. {
  310. if (virtualPathsToIgnore == null)
  311. virtualPathsToIgnore = new Dictionary <string, bool> (RuntimeHelpers.StringEqualityComparerCulture);
  312. VirtualPath path = GetAbsoluteVirtualPath (vp);
  313. string vpAbsolute = path.Absolute;
  314. if (!virtualPathsToIgnore.ContainsKey (vpAbsolute)) {
  315. virtualPathsToIgnore.Add (vpAbsolute, true);
  316. haveVirtualPathsToIgnore = true;
  317. }
  318. string vpRelative = path.AppRelative;
  319. if (!virtualPathsToIgnore.ContainsKey (vpRelative)) {
  320. virtualPathsToIgnore.Add (vpRelative, true);
  321. haveVirtualPathsToIgnore = true;
  322. }
  323. if (!virtualPathsToIgnore.ContainsKey (vp)) {
  324. virtualPathsToIgnore.Add (vp, true);
  325. haveVirtualPathsToIgnore = true;
  326. }
  327. }
  328. internal static void AddToReferencedAssemblies (Assembly asm)
  329. {
  330. // should not be used
  331. }
  332. static void AssertVirtualPathExists (VirtualPath virtualPath)
  333. {
  334. string realpath;
  335. bool dothrow = false;
  336. if (virtualPath.IsFake) {
  337. realpath = virtualPath.PhysicalPath;
  338. if (!File.Exists (realpath) && !Directory.Exists (realpath))
  339. dothrow = true;
  340. } else {
  341. VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
  342. string vpAbsolute = virtualPath.Absolute;
  343. if (!vpp.FileExists (vpAbsolute) && !vpp.DirectoryExists (vpAbsolute))
  344. dothrow = true;
  345. }
  346. if (dothrow)
  347. throw new HttpException (404, "The file '" + virtualPath + "' does not exist.", virtualPath.Absolute);
  348. }
  349. static void Build (VirtualPath vp)
  350. {
  351. AssertVirtualPathExists (vp);
  352. CompilationSection cs = CompilationConfig;
  353. lock (bigCompilationLock) {
  354. bool entryExists;
  355. if (HasCachedItemNoLock (vp.Absolute, out entryExists))
  356. return;
  357. if (recursionDepth == 0)
  358. referencedAssemblies.Clear ();
  359. recursionDepth++;
  360. try {
  361. BuildInner (vp, cs != null ? cs.Debug : false);
  362. if (entryExists && recursionDepth <= 1)
  363. // We count only update builds - first time a file
  364. // (or a batch) is built doesn't count.
  365. buildCount++;
  366. } finally {
  367. // See http://support.microsoft.com/kb/319947
  368. if (buildCount > cs.NumRecompilesBeforeAppRestart)
  369. HttpRuntime.UnloadAppDomain ();
  370. recursionDepth--;
  371. }
  372. }
  373. }
  374. // This method assumes it is being called with the big compilation lock held
  375. static void BuildInner (VirtualPath vp, bool debug)
  376. {
  377. var builder = new BuildManagerDirectoryBuilder (vp);
  378. bool recursive = recursionDepth > 1;
  379. List <BuildProviderGroup> builderGroups = builder.Build (IsSingleBuild (vp, recursive));
  380. if (builderGroups == null)
  381. return;
  382. string vpabsolute = vp.Absolute;
  383. int buildHash = (vpabsolute.GetHashCode () | (int)DateTime.Now.Ticks) + (int)recursionDepth;
  384. string assemblyBaseName;
  385. AssemblyBuilder abuilder;
  386. CompilerType ct;
  387. int attempts;
  388. bool singleBuild, needMainVpBuild;
  389. CompilationException compilationError;
  390. // Each group becomes a separate assembly.
  391. foreach (BuildProviderGroup group in builderGroups) {
  392. needMainVpBuild = false;
  393. compilationError = null;
  394. assemblyBaseName = null;
  395. if (group.Count == 1) {
  396. if (recursive || !group.Master)
  397. assemblyBaseName = String.Format ("{0}_{1}.{2:x}.", group.NamePrefix, VirtualPathUtility.GetFileName (group [0].VirtualPath), buildHash);
  398. singleBuild = true;
  399. } else
  400. singleBuild = false;
  401. if (assemblyBaseName == null)
  402. assemblyBaseName = group.NamePrefix + "_";
  403. ct = group.CompilerType;
  404. attempts = 3;
  405. while (attempts > 0) {
  406. abuilder = new AssemblyBuilder (vp, CreateDomProvider (ct), assemblyBaseName);
  407. abuilder.CompilerOptions = ct.CompilerParameters;
  408. abuilder.AddAssemblyReference (GetReferencedAssemblies () as List <Assembly>);
  409. try {
  410. GenerateAssembly (abuilder, group, vp, debug);
  411. attempts = 0;
  412. } catch (CompilationException ex) {
  413. attempts--;
  414. if (singleBuild)
  415. throw new HttpException ("Single file build failed.", ex);
  416. if (attempts == 0) {
  417. needMainVpBuild = true;
  418. compilationError = ex;
  419. break;
  420. }
  421. CompilerResults results = ex.Results;
  422. if (results == null)
  423. throw new HttpException ("No results returned from failed compilation.", ex);
  424. else
  425. RemoveFailedAssemblies (vpabsolute, ex, abuilder, group, results, debug);
  426. }
  427. }
  428. if (needMainVpBuild) {
  429. // One last attempt - try to build just the requested path
  430. // if it's not built yet or just return without throwing the
  431. // exception if it has already been built.
  432. if (HasCachedItemNoLock (vpabsolute)) {
  433. if (debug)
  434. DescribeCompilationError ("Path '{0}' built successfully, but a compilation exception has been thrown for other files:",
  435. compilationError, vpabsolute);
  436. return;
  437. };
  438. // This will trigger a recursive build of the requested vp,
  439. // which means only the vp alone will be built (or not);
  440. Build (vp);
  441. if (HasCachedItemNoLock (vpabsolute)) {
  442. if (debug)
  443. DescribeCompilationError ("Path '{0}' built successfully, but a compilation exception has been thrown for other files:",
  444. compilationError, vpabsolute);
  445. return;
  446. }
  447. // In theory this code is unreachable. If the recursive
  448. // build of the main vp failed, then it should have thrown
  449. // the build exception.
  450. throw new HttpException ("Requested virtual path build failed.", compilationError);
  451. }
  452. }
  453. }
  454. static CodeDomProvider CreateDomProvider (CompilerType ct)
  455. {
  456. if (codeDomProviders == null)
  457. codeDomProviders = new Dictionary <Type, CodeDomProvider> ();
  458. Type type = ct.CodeDomProviderType;
  459. if (type == null) {
  460. CompilationSection cs = CompilationConfig;
  461. CompilerType tmp = GetDefaultCompilerTypeForLanguage (cs.DefaultLanguage, cs);
  462. if (tmp != null)
  463. type = tmp.CodeDomProviderType;
  464. }
  465. if (type == null)
  466. return null;
  467. CodeDomProvider ret;
  468. if (codeDomProviders.TryGetValue (type, out ret))
  469. return ret;
  470. ret = Activator.CreateInstance (type) as CodeDomProvider;
  471. if (ret == null)
  472. return null;
  473. codeDomProviders.Add (type, ret);
  474. return ret;
  475. }
  476. #if NET_4_0
  477. internal static void CallPreStartMethods ()
  478. {
  479. if (preStartMethodsDone)
  480. return;
  481. preStartMethodsRunning = true;
  482. MethodInfo mi = null;
  483. try {
  484. List <MethodInfo> methods = LoadPreStartMethodsFromAssemblies (GetReferencedAssemblies () as List <Assembly>);
  485. if (methods == null || methods.Count == 0)
  486. return;
  487. foreach (MethodInfo m in methods) {
  488. mi = m;
  489. m.Invoke (null, null);
  490. }
  491. } catch (Exception ex) {
  492. throw new HttpException (
  493. String.Format ("The pre-application start initialization method {0} on type {1} threw an exception with the following error message: {2}",
  494. mi != null ? mi.Name : "UNKNOWN",
  495. mi != null ? mi.DeclaringType.FullName : "UNKNOWN",
  496. ex.Message),
  497. ex
  498. );
  499. } finally {
  500. preStartMethodsRunning = false;
  501. preStartMethodsDone = true;
  502. }
  503. }
  504. static List <MethodInfo> LoadPreStartMethodsFromAssemblies (List <Assembly> assemblies)
  505. {
  506. if (assemblies == null || assemblies.Count == 0)
  507. return null;
  508. var ret = new List <MethodInfo> ();
  509. object[] attributes;
  510. Type type;
  511. PreApplicationStartMethodAttribute attr;
  512. foreach (Assembly asm in assemblies) {
  513. try {
  514. attributes = asm.GetCustomAttributes (typeof (PreApplicationStartMethodAttribute), false);
  515. if (attributes == null || attributes.Length == 0)
  516. continue;
  517. attr = attributes [0] as PreApplicationStartMethodAttribute;
  518. type = attr.Type;
  519. if (type == null)
  520. continue;
  521. } catch {
  522. continue;
  523. }
  524. MethodInfo mi;
  525. Exception error = null;
  526. try {
  527. if (type.IsPublic)
  528. mi = type.GetMethod (attr.MethodName, BindingFlags.Static | BindingFlags.Public, null, new Type[] {}, null);
  529. else
  530. mi = null;
  531. } catch (Exception ex) {
  532. error = ex;
  533. mi = null;
  534. }
  535. if (mi == null)
  536. throw new HttpException (
  537. String.Format (
  538. "The method specified by the PreApplicationStartMethodAttribute on assembly '{0}' cannot be resolved. Type: '{1}', MethodName: '{2}'. Verify that the type is public and the method is public and static (Shared in Visual Basic).",
  539. asm.FullName,
  540. type.FullName,
  541. attr.MethodName),
  542. error
  543. );
  544. ret.Add (mi);
  545. }
  546. return ret;
  547. }
  548. public static Type GetGlobalAsaxType ()
  549. {
  550. Type ret = HttpApplicationFactory.AppType;
  551. if (ret == null)
  552. return typeof (HttpApplication);
  553. return ret;
  554. }
  555. public static Stream CreateCachedFile (string fileName)
  556. {
  557. if (fileName != null && (fileName == String.Empty || fileName.IndexOf (Path.DirectorySeparatorChar) != -1))
  558. throw new ArgumentException ("Value does not fall within the expected range.");
  559. string path = Path.Combine (HttpRuntime.CodegenDir, fileName);
  560. return new FileStream (path, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
  561. }
  562. public static Stream ReadCachedFile (string fileName)
  563. {
  564. if (fileName != null && (fileName == String.Empty || fileName.IndexOf (Path.DirectorySeparatorChar) != -1))
  565. throw new ArgumentException ("Value does not fall within the expected range.");
  566. string path = Path.Combine (HttpRuntime.CodegenDir, fileName);
  567. if (!File.Exists (path))
  568. return null;
  569. return new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.None);
  570. }
  571. [MonoDocumentationNote ("Fully implemented but no info on application pre-init stage is available yet.")]
  572. public static void AddReferencedAssembly (Assembly assembly)
  573. {
  574. if (assembly == null)
  575. throw new ArgumentNullException ("assembly");
  576. if (preStartMethodsDone)
  577. throw new InvalidOperationException ("This method cannot be called after the application's pre-start initialization stage.");
  578. if (dynamicallyRegisteredAssemblies == null)
  579. dynamicallyRegisteredAssemblies = new List <Assembly> ();
  580. if (!dynamicallyRegisteredAssemblies.Contains (assembly))
  581. dynamicallyRegisteredAssemblies.Add (assembly);
  582. }
  583. [MonoDocumentationNote ("Not used by Mono internally. Needed for MVC3")]
  584. public static IWebObjectFactory GetObjectFactory (string virtualPath, bool throwIfNotFound)
  585. {
  586. if (CompilingTopLevelAssemblies)
  587. throw new HttpException ("Method must not be called while compiling the top level assemblies.");
  588. Type type;
  589. if (is_precompiled) {
  590. type = GetPrecompiledType (virtualPath);
  591. if (type == null) {
  592. if (throwIfNotFound)
  593. throw new HttpException (String.Format ("Virtual path '{0}' not found in precompiled application type cache.", virtualPath));
  594. else
  595. return null;
  596. }
  597. return new SimpleWebObjectFactory (type);
  598. }
  599. Exception compileException = null;
  600. try {
  601. type = GetCompiledType (virtualPath);
  602. } catch (Exception ex) {
  603. compileException = ex;
  604. type = null;
  605. }
  606. if (type == null) {
  607. if (throwIfNotFound)
  608. throw new HttpException (String.Format ("Virtual path '{0}' does not exist.", virtualPath), compileException);
  609. return null;
  610. }
  611. return new SimpleWebObjectFactory (type);
  612. }
  613. #endif
  614. public static object CreateInstanceFromVirtualPath (string virtualPath, Type requiredBaseType)
  615. {
  616. return CreateInstanceFromVirtualPath (GetAbsoluteVirtualPath (virtualPath), requiredBaseType);
  617. }
  618. internal static object CreateInstanceFromVirtualPath (VirtualPath virtualPath, Type requiredBaseType)
  619. {
  620. if (requiredBaseType == null)
  621. throw new NullReferenceException (); // This is what MS does, but
  622. // from somewhere else.
  623. Type type = GetCompiledType (virtualPath);
  624. if (type == null)
  625. return null;
  626. if (!requiredBaseType.IsAssignableFrom (type))
  627. throw new HttpException (500,
  628. String.Format ("Type '{0}' does not inherit from '{1}'.", type.FullName, requiredBaseType.FullName));
  629. return Activator.CreateInstance (type, null);
  630. }
  631. static void DescribeCompilationError (string format, CompilationException ex, params object[] parms)
  632. {
  633. StringBuilder sb = new StringBuilder ();
  634. string newline = Environment.NewLine;
  635. if (parms != null)
  636. sb.AppendFormat (format + newline, parms);
  637. else
  638. sb.Append (format + newline);
  639. CompilerResults results = ex != null ? ex.Results : null;
  640. if (results == null)
  641. sb.Append ("No compiler error information present." + newline);
  642. else {
  643. sb.Append ("Compiler errors:" + newline);
  644. foreach (CompilerError error in results.Errors)
  645. sb.Append (" " + error.ToString () + newline);
  646. }
  647. if (ex != null) {
  648. sb.Append (newline + "Exception thrown:" + newline);
  649. sb.Append (ex.ToString ());
  650. }
  651. ShowDebugModeMessage (sb.ToString ());
  652. }
  653. static BuildProvider FindBuildProviderForPhysicalPath (string path, BuildProviderGroup group, HttpRequest req)
  654. {
  655. if (req == null || String.IsNullOrEmpty (path))
  656. return null;
  657. foreach (BuildProvider bp in group) {
  658. if (String.Compare (path, req.MapPath (bp.VirtualPath), RuntimeHelpers.StringComparison) == 0)
  659. return bp;
  660. }
  661. return null;
  662. }
  663. static void GenerateAssembly (AssemblyBuilder abuilder, BuildProviderGroup group, VirtualPath vp, bool debug)
  664. {
  665. IDictionary <string, bool> deps;
  666. BuildManagerCacheItem bmci;
  667. string bvp, vpabsolute = vp.Absolute;
  668. StringBuilder sb;
  669. string newline;
  670. int failedCount = 0;
  671. if (debug) {
  672. newline = Environment.NewLine;
  673. sb = new StringBuilder ("Code generation for certain virtual paths in a batch failed. Those files have been removed from the batch." + newline);
  674. sb.Append ("Since you're running in debug mode, here's some more information about the error:" + newline);
  675. } else {
  676. newline = null;
  677. sb = null;
  678. }
  679. List <BuildProvider> failedBuildProviders = null;
  680. StringComparison stringComparison = RuntimeHelpers.StringComparison;
  681. foreach (BuildProvider bp in group) {
  682. bvp = bp.VirtualPath;
  683. if (HasCachedItemNoLock (bvp))
  684. continue;
  685. try {
  686. bp.GenerateCode (abuilder);
  687. } catch (Exception ex) {
  688. if (String.Compare (bvp, vpabsolute, stringComparison) == 0) {
  689. if (ex is CompilationException || ex is ParseException)
  690. throw;
  691. throw new HttpException ("Code generation failed.", ex);
  692. }
  693. if (failedBuildProviders == null)
  694. failedBuildProviders = new List <BuildProvider> ();
  695. failedBuildProviders.Add (bp);
  696. failedCount++;
  697. if (sb != null) {
  698. if (failedCount > 1)
  699. sb.Append (newline);
  700. sb.AppendFormat ("Failed file virtual path: {0}; Exception: {1}{2}{1}", bp.VirtualPath, newline, ex);
  701. }
  702. continue;
  703. }
  704. deps = bp.ExtractDependencies ();
  705. if (deps != null) {
  706. foreach (var dep in deps) {
  707. bmci = GetCachedItemNoLock (dep.Key);
  708. if (bmci == null || bmci.BuiltAssembly == null)
  709. continue;
  710. abuilder.AddAssemblyReference (bmci.BuiltAssembly);
  711. }
  712. }
  713. }
  714. if (sb != null && failedCount > 0)
  715. ShowDebugModeMessage (sb.ToString ());
  716. if (failedBuildProviders != null) {
  717. foreach (BuildProvider bp in failedBuildProviders)
  718. group.Remove (bp);
  719. }
  720. foreach (Assembly asm in referencedAssemblies) {
  721. if (asm == null)
  722. continue;
  723. abuilder.AddAssemblyReference (asm);
  724. }
  725. CompilerResults results = abuilder.BuildAssembly (vp);
  726. // No results is not an error - it is possible that the assembly builder contained only .asmx and
  727. // .ashx files which had no body, just the directive. In such case, no code unit or code file is added
  728. // to the assembly builder and, in effect, no assembly is produced but there are STILL types that need
  729. // to be added to the cache.
  730. Assembly compiledAssembly = results != null ? results.CompiledAssembly : null;
  731. try {
  732. #if SYSTEMCORE_DEP
  733. buildCacheLock.EnterWriteLock ();
  734. #else
  735. buildCacheLock.AcquireWriterLock (-1);
  736. #endif
  737. if (compiledAssembly != null)
  738. referencedAssemblies.Add (compiledAssembly);
  739. foreach (BuildProvider bp in group) {
  740. if (HasCachedItemNoLock (bp.VirtualPath))
  741. continue;
  742. StoreInCache (bp, compiledAssembly, results);
  743. }
  744. } finally {
  745. #if SYSTEMCORE_DEP
  746. buildCacheLock.ExitWriteLock ();
  747. #else
  748. buildCacheLock.ReleaseWriterLock ();
  749. #endif
  750. }
  751. }
  752. static VirtualPath GetAbsoluteVirtualPath (string virtualPath)
  753. {
  754. string vp;
  755. if (!VirtualPathUtility.IsRooted (virtualPath)) {
  756. HttpContext ctx = HttpContext.Current;
  757. HttpRequest req = ctx != null ? ctx.Request : null;
  758. if (req != null) {
  759. string fileDir = req.FilePath;
  760. if (!String.IsNullOrEmpty (fileDir) && String.Compare (fileDir, "/", StringComparison.Ordinal) != 0)
  761. fileDir = VirtualPathUtility.GetDirectory (fileDir);
  762. else
  763. fileDir = "/";
  764. vp = VirtualPathUtility.Combine (fileDir, virtualPath);
  765. } else
  766. throw new HttpException ("No context, cannot map paths.");
  767. } else
  768. vp = virtualPath;
  769. return new VirtualPath (vp);
  770. }
  771. [MonoTODO ("Not implemented, always returns null")]
  772. public static BuildDependencySet GetCachedBuildDependencySet (HttpContext context, string virtualPath)
  773. {
  774. return null; // null is ok here until we store the dependency set in the Cache.
  775. }
  776. #if NET_4_0
  777. [MonoTODO ("Not implemented, always returns null")]
  778. public static BuildDependencySet GetCachedBuildDependencySet (HttpContext context, string virtualPath, bool ensureIsUpToDate)
  779. {
  780. return null; // null is ok here until we store the dependency set in the Cache.
  781. }
  782. #endif
  783. static BuildManagerCacheItem GetCachedItem (string vp)
  784. {
  785. try {
  786. #if SYSTEMCORE_DEP
  787. buildCacheLock.EnterReadLock ();
  788. #else
  789. buildCacheLock.AcquireReaderLock (-1);
  790. #endif
  791. return GetCachedItemNoLock (vp);
  792. } finally {
  793. #if SYSTEMCORE_DEP
  794. buildCacheLock.ExitReadLock ();
  795. #else
  796. buildCacheLock.ReleaseReaderLock ();
  797. #endif
  798. }
  799. }
  800. static BuildManagerCacheItem GetCachedItemNoLock (string vp)
  801. {
  802. BuildManagerCacheItem ret;
  803. if (buildCache.TryGetValue (vp, out ret))
  804. return ret;
  805. return null;
  806. }
  807. internal static Type GetCodeDomProviderType (BuildProvider provider)
  808. {
  809. CompilerType codeCompilerType;
  810. Type codeDomProviderType = null;
  811. codeCompilerType = provider.CodeCompilerType;
  812. if (codeCompilerType != null)
  813. codeDomProviderType = codeCompilerType.CodeDomProviderType;
  814. if (codeDomProviderType == null)
  815. throw new HttpException (String.Concat ("Provider '", provider, " 'fails to specify the compiler type."));
  816. return codeDomProviderType;
  817. }
  818. static Type GetPrecompiledType (string virtualPath)
  819. {
  820. PreCompilationData pc_data;
  821. if (precompiled != null && precompiled.TryGetValue (virtualPath, out pc_data)) {
  822. if (pc_data.Type == null) {
  823. pc_data.Type = Type.GetType (pc_data.TypeName + ", " + pc_data.AssemblyFileName, true);
  824. }
  825. return pc_data.Type;
  826. }
  827. return null;
  828. }
  829. internal static Type GetPrecompiledApplicationType ()
  830. {
  831. if (!is_precompiled)
  832. return null;
  833. Type apptype = GetPrecompiledType (VirtualPathUtility.Combine (HttpRuntime.AppDomainAppVirtualPath, "Global.asax"));
  834. if (apptype == null)
  835. apptype = GetPrecompiledType (VirtualPathUtility.Combine (HttpRuntime.AppDomainAppVirtualPath , "global.asax"));
  836. return apptype;
  837. }
  838. public static Assembly GetCompiledAssembly (string virtualPath)
  839. {
  840. return GetCompiledAssembly (GetAbsoluteVirtualPath (virtualPath));
  841. }
  842. internal static Assembly GetCompiledAssembly (VirtualPath virtualPath)
  843. {
  844. string vpabsolute = virtualPath.Absolute;
  845. if (is_precompiled) {
  846. Type type = GetPrecompiledType (vpabsolute);
  847. if (type != null)
  848. return type.Assembly;
  849. }
  850. BuildManagerCacheItem bmci = GetCachedItem (vpabsolute);
  851. if (bmci != null)
  852. return bmci.BuiltAssembly;
  853. Build (virtualPath);
  854. bmci = GetCachedItem (vpabsolute);
  855. if (bmci != null)
  856. return bmci.BuiltAssembly;
  857. return null;
  858. }
  859. public static Type GetCompiledType (string virtualPath)
  860. {
  861. return GetCompiledType (GetAbsoluteVirtualPath (virtualPath));
  862. }
  863. internal static Type GetCompiledType (VirtualPath virtualPath)
  864. {
  865. string vpabsolute = virtualPath.Absolute;
  866. if (is_precompiled) {
  867. Type type = GetPrecompiledType (vpabsolute);
  868. if (type != null)
  869. return type;
  870. }
  871. BuildManagerCacheItem bmci = GetCachedItem (vpabsolute);
  872. if (bmci != null) {
  873. ReferenceAssemblyInCompilation (bmci);
  874. return bmci.Type;
  875. }
  876. Build (virtualPath);
  877. bmci = GetCachedItem (vpabsolute);
  878. if (bmci != null) {
  879. ReferenceAssemblyInCompilation (bmci);
  880. return bmci.Type;
  881. }
  882. return null;
  883. }
  884. public static string GetCompiledCustomString (string virtualPath)
  885. {
  886. return GetCompiledCustomString (GetAbsoluteVirtualPath (virtualPath));
  887. }
  888. internal static string GetCompiledCustomString (VirtualPath virtualPath)
  889. {
  890. string vpabsolute = virtualPath.Absolute;
  891. BuildManagerCacheItem bmci = GetCachedItem (vpabsolute);
  892. if (bmci != null)
  893. return bmci.CompiledCustomString;
  894. Build (virtualPath);
  895. bmci = GetCachedItem (vpabsolute);
  896. if (bmci != null)
  897. return bmci.CompiledCustomString;
  898. return null;
  899. }
  900. internal static CompilerType GetDefaultCompilerTypeForLanguage (string language, CompilationSection configSection)
  901. {
  902. return GetDefaultCompilerTypeForLanguage (language, configSection, true);
  903. }
  904. internal static CompilerType GetDefaultCompilerTypeForLanguage (string language, CompilationSection configSection, bool throwOnMissing)
  905. {
  906. // MS throws when accesing a Hashtable, we do here.
  907. if (language == null || language.Length == 0)
  908. throw new ArgumentNullException ("language");
  909. CompilationSection config;
  910. if (configSection == null)
  911. config = WebConfigurationManager.GetWebApplicationSection ("system.web/compilation") as CompilationSection;
  912. else
  913. config = configSection;
  914. Compiler compiler = config.Compilers.Get (language);
  915. CompilerParameters p;
  916. Type type;
  917. if (compiler != null) {
  918. type = HttpApplication.LoadType (compiler.Type, true);
  919. p = new CompilerParameters ();
  920. p.CompilerOptions = compiler.CompilerOptions;
  921. p.WarningLevel = compiler.WarningLevel;
  922. SetCommonParameters (config, p, type, language);
  923. return new CompilerType (type, p);
  924. }
  925. if (CodeDomProvider.IsDefinedLanguage (language)) {
  926. CompilerInfo info = CodeDomProvider.GetCompilerInfo (language);
  927. p = info.CreateDefaultCompilerParameters ();
  928. type = info.CodeDomProviderType;
  929. SetCommonParameters (config, p, type, language);
  930. return new CompilerType (type, p);
  931. }
  932. if (throwOnMissing)
  933. throw new HttpException (String.Concat ("No compiler for language '", language, "'."));
  934. return null;
  935. }
  936. public static ICollection GetReferencedAssemblies ()
  937. {
  938. if (getReferencedAssembliesInvoked)
  939. return configReferencedAssemblies;
  940. if (allowReferencedAssembliesCaching)
  941. getReferencedAssembliesInvoked = true;
  942. if (configReferencedAssemblies == null)
  943. configReferencedAssemblies = new List <Assembly> ();
  944. else if (getReferencedAssembliesInvoked)
  945. configReferencedAssemblies.Clear ();
  946. CompilationSection compConfig = WebConfigurationManager.GetWebApplicationSection ("system.web/compilation") as CompilationSection;
  947. if (compConfig == null)
  948. return configReferencedAssemblies;
  949. bool addAssembliesInBin = false;
  950. foreach (AssemblyInfo info in compConfig.Assemblies) {
  951. if (info.Assembly == "*")
  952. addAssembliesInBin = is_precompiled ? false : true;
  953. else
  954. LoadAssembly (info, configReferencedAssemblies);
  955. }
  956. foreach (Assembly topLevelAssembly in TopLevelAssemblies)
  957. configReferencedAssemblies.Add (topLevelAssembly);
  958. foreach (string assLocation in WebConfigurationManager.ExtraAssemblies)
  959. LoadAssembly (assLocation, configReferencedAssemblies);
  960. #if NET_4_0
  961. if (dynamicallyRegisteredAssemblies != null)
  962. foreach (Assembly registeredAssembly in dynamicallyRegisteredAssemblies)
  963. configReferencedAssemblies.Add (registeredAssembly);
  964. #endif
  965. // Precompiled sites unconditionally load all assemblies from bin/ (fix for
  966. // bug #502016)
  967. if (is_precompiled || addAssembliesInBin) {
  968. foreach (string s in HttpApplication.BinDirectoryAssemblies) {
  969. try {
  970. LoadAssembly (s, configReferencedAssemblies);
  971. } catch (BadImageFormatException) {
  972. // ignore silently
  973. }
  974. }
  975. }
  976. return configReferencedAssemblies;
  977. }
  978. // The 2 GetType() overloads work on the global.asax, App_GlobalResources, App_WebReferences or App_Browsers
  979. public static Type GetType (string typeName, bool throwOnError)
  980. {
  981. return GetType (typeName, throwOnError, false);
  982. }
  983. public static Type GetType (string typeName, bool throwOnError, bool ignoreCase)
  984. {
  985. Type ret = null;
  986. try {
  987. foreach (Assembly asm in TopLevel_Assemblies) {
  988. ret = asm.GetType (typeName, throwOnError, ignoreCase);
  989. if (ret != null)
  990. break;
  991. }
  992. } catch (Exception ex) {
  993. throw new HttpException ("Failed to find the specified type.", ex);
  994. }
  995. return ret;
  996. }
  997. public static ICollection GetVirtualPathDependencies (string virtualPath)
  998. {
  999. return GetVirtualPathDependencies (virtualPath, null);
  1000. }
  1001. internal static ICollection GetVirtualPathDependencies (string virtualPath, BuildProvider bprovider)
  1002. {
  1003. BuildProvider provider = bprovider;
  1004. if (provider == null) {
  1005. CompilationSection cs = CompilationConfig;
  1006. if (cs == null)
  1007. return null;
  1008. provider = BuildManagerDirectoryBuilder.GetBuildProvider (virtualPath, cs.BuildProviders);
  1009. }
  1010. if (provider == null)
  1011. return null;
  1012. IDictionary <string, bool> deps = provider.ExtractDependencies ();
  1013. if (deps == null)
  1014. return null;
  1015. return (ICollection)deps.Keys;
  1016. }
  1017. internal static bool HasCachedItemNoLock (string vp, out bool entryExists)
  1018. {
  1019. BuildManagerCacheItem item;
  1020. if (buildCache.TryGetValue (vp, out item)) {
  1021. entryExists = true;
  1022. return item != null;
  1023. }
  1024. entryExists = false;
  1025. return false;
  1026. }
  1027. internal static bool HasCachedItemNoLock (string vp)
  1028. {
  1029. bool dummy;
  1030. return HasCachedItemNoLock (vp, out dummy);
  1031. }
  1032. internal static bool IgnoreVirtualPath (string virtualPath)
  1033. {
  1034. if (!virtualPathsToIgnoreChecked) {
  1035. lock (virtualPathsToIgnoreLock) {
  1036. if (!virtualPathsToIgnoreChecked)
  1037. LoadVirtualPathsToIgnore ();
  1038. virtualPathsToIgnoreChecked = true;
  1039. }
  1040. }
  1041. if (!haveVirtualPathsToIgnore)
  1042. return false;
  1043. if (virtualPathsToIgnore.ContainsKey (virtualPath))
  1044. return true;
  1045. return false;
  1046. }
  1047. static bool IsSingleBuild (VirtualPath vp, bool recursive)
  1048. {
  1049. if (String.Compare (vp.AppRelative, "~/global.asax", StringComparison.OrdinalIgnoreCase) == 0)
  1050. return true;
  1051. if (!BatchMode)
  1052. return true;
  1053. return recursive;
  1054. }
  1055. static void LoadAssembly (string path, List <Assembly> al)
  1056. {
  1057. AddAssembly (Assembly.LoadFrom (path), al);
  1058. }
  1059. static void LoadAssembly (AssemblyInfo info, List <Assembly> al)
  1060. {
  1061. AddAssembly (Assembly.Load (info.Assembly), al);
  1062. }
  1063. static void LoadVirtualPathsToIgnore ()
  1064. {
  1065. NameValueCollection appSettings = WebConfigurationManager.AppSettings;
  1066. if (appSettings == null)
  1067. return;
  1068. string pathsFromConfig = appSettings ["MonoAspnetBatchCompileIgnorePaths"];
  1069. string pathsFromFile = appSettings ["MonoAspnetBatchCompileIgnoreFromFile"];
  1070. if (!String.IsNullOrEmpty (pathsFromConfig)) {
  1071. string[] paths = pathsFromConfig.Split (virtualPathsToIgnoreSplitChars);
  1072. string path;
  1073. foreach (string p in paths) {
  1074. path = p.Trim ();
  1075. if (path.Length == 0)
  1076. continue;
  1077. AddPathToIgnore (path);
  1078. }
  1079. }
  1080. if (!String.IsNullOrEmpty (pathsFromFile)) {
  1081. string realpath;
  1082. HttpContext ctx = HttpContext.Current;
  1083. HttpRequest req = ctx != null ? ctx.Request : null;
  1084. if (req == null)
  1085. throw new HttpException ("Missing context, cannot continue.");
  1086. realpath = req.MapPath (pathsFromFile);
  1087. if (!File.Exists (realpath))
  1088. return;
  1089. string[] paths = File.ReadAllLines (realpath);
  1090. if (paths == null || paths.Length == 0)
  1091. return;
  1092. string path;
  1093. foreach (string p in paths) {
  1094. path = p.Trim ();
  1095. if (path.Length == 0)
  1096. continue;
  1097. AddPathToIgnore (path);
  1098. }
  1099. }
  1100. }
  1101. static void OnEntryRemoved (string vp)
  1102. {
  1103. BuildManagerRemoveEntryEventHandler eh = events [buildManagerRemoveEntryEvent] as BuildManagerRemoveEntryEventHandler;
  1104. if (eh != null)
  1105. eh (new BuildManagerRemoveEntryEventArgs (vp, HttpContext.Current));
  1106. }
  1107. static void OnVirtualPathChanged (string key, object value, CacheItemRemovedReason removedReason)
  1108. {
  1109. string virtualPath;
  1110. if (StrUtils.StartsWith (key, BUILD_MANAGER_VIRTUAL_PATH_CACHE_PREFIX))
  1111. virtualPath = key.Substring (BUILD_MANAGER_VIRTUAL_PATH_CACHE_PREFIX_LENGTH);
  1112. else
  1113. return;
  1114. try {
  1115. #if SYSTEMCORE_DEP
  1116. buildCacheLock.EnterWriteLock ();
  1117. #else
  1118. buildCacheLock.AcquireWriterLock (-1);
  1119. #endif
  1120. if (HasCachedItemNoLock (virtualPath)) {
  1121. buildCache [virtualPath] = null;
  1122. OnEntryRemoved (virtualPath);
  1123. }
  1124. } finally {
  1125. #if SYSTEMCORE_DEP
  1126. buildCacheLock.ExitWriteLock ();
  1127. #else
  1128. buildCacheLock.ReleaseWriterLock ();
  1129. #endif
  1130. }
  1131. }
  1132. static void ReferenceAssemblyInCompilation (BuildManagerCacheItem bmci)
  1133. {
  1134. if (recursionDepth == 0 || referencedAssemblies.Contains (bmci.BuiltAssembly))
  1135. return;
  1136. referencedAssemblies.Add (bmci.BuiltAssembly);
  1137. }
  1138. static void RemoveFailedAssemblies (string requestedVirtualPath, CompilationException ex, AssemblyBuilder abuilder,
  1139. BuildProviderGroup group, CompilerResults results, bool debug)
  1140. {
  1141. StringBuilder sb;
  1142. string newline;
  1143. if (debug) {
  1144. newline = Environment.NewLine;
  1145. sb = new StringBuilder ("Compilation of certain files in a batch failed. Another attempt to compile the batch will be made." + newline);
  1146. sb.Append ("Since you're running in debug mode, here's some more information about the error:" + newline);
  1147. } else {
  1148. newline = null;
  1149. sb = null;
  1150. }
  1151. var failedBuildProviders = new List <BuildProvider> ();
  1152. BuildProvider bp;
  1153. HttpContext ctx = HttpContext.Current;
  1154. HttpRequest req = ctx != null ? ctx.Request : null;
  1155. bool rethrow = false;
  1156. foreach (CompilerError error in results.Errors) {
  1157. if (error.IsWarning)
  1158. continue;
  1159. bp = abuilder.GetBuildProviderForPhysicalFilePath (error.FileName);
  1160. if (bp == null) {
  1161. bp = FindBuildProviderForPhysicalPath (error.FileName, group, req);
  1162. if (bp == null)
  1163. continue;
  1164. }
  1165. if (String.Compare (bp.VirtualPath, requestedVirtualPath, StringComparison.Ordinal) == 0)
  1166. rethrow = true;
  1167. if (!failedBuildProviders.Contains (bp)) {
  1168. failedBuildProviders.Add (bp);
  1169. if (sb != null)
  1170. sb.AppendFormat ("\t{0}{1}", bp.VirtualPath, newline);
  1171. }
  1172. if (sb != null)
  1173. sb.AppendFormat ("\t\t{0}{1}", error, newline);
  1174. }
  1175. foreach (BuildProvider fbp in failedBuildProviders)
  1176. group.Remove (fbp);
  1177. if (sb != null) {
  1178. sb.AppendFormat ("{0}The following exception has been thrown for the file(s) listed above:{0}{1}",
  1179. newline, ex.ToString ());
  1180. ShowDebugModeMessage (sb.ToString ());
  1181. sb = null;
  1182. }
  1183. if (rethrow)
  1184. throw new HttpException ("Compilation failed.", ex);
  1185. }
  1186. static void SetCommonParameters (CompilationSection config, CompilerParameters p, Type compilerType, string language)
  1187. {
  1188. p.IncludeDebugInformation = config.Debug;
  1189. MonoSettingsSection mss = WebConfigurationManager.GetSection ("system.web/monoSettings") as MonoSettingsSection;
  1190. if (mss == null || !mss.UseCompilersCompatibility)
  1191. return;
  1192. Compiler compiler = mss.CompilersCompatibility.Get (language);
  1193. if (compiler == null)
  1194. return;
  1195. Type type = HttpApplication.LoadType (compiler.Type, false);
  1196. if (type != compilerType)
  1197. return;
  1198. p.CompilerOptions = String.Concat (p.CompilerOptions, " ", compiler.CompilerOptions);
  1199. }
  1200. static void ShowDebugModeMessage (string msg)
  1201. {
  1202. if (suppressDebugModeMessages)
  1203. return;
  1204. Console.WriteLine ();
  1205. Console.WriteLine ("******* DEBUG MODE MESSAGE *******");
  1206. Console.WriteLine (msg);
  1207. Console.WriteLine ("******* DEBUG MODE MESSAGE *******");
  1208. Console.WriteLine ();
  1209. }
  1210. static void StoreInCache (BuildProvider bp, Assembly compiledAssembly, CompilerResults results)
  1211. {
  1212. string virtualPath = bp.VirtualPath;
  1213. var item = new BuildManagerCacheItem (compiledAssembly, bp, results);
  1214. if (buildCache.ContainsKey (virtualPath))
  1215. buildCache [virtualPath] = item;
  1216. else
  1217. buildCache.Add (virtualPath, item);
  1218. HttpContext ctx = HttpContext.Current;
  1219. HttpRequest req = ctx != null ? ctx.Request : null;
  1220. CacheDependency dep;
  1221. if (req != null) {
  1222. IDictionary <string, bool> deps = bp.ExtractDependencies ();
  1223. var files = new List <string> ();
  1224. string physicalPath;
  1225. physicalPath = req.MapPath (virtualPath);
  1226. if (File.Exists (physicalPath))
  1227. files.Add (physicalPath);
  1228. if (deps != null && deps.Count > 0) {
  1229. foreach (var d in deps) {
  1230. physicalPath = req.MapPath (d.Key);
  1231. if (!File.Exists (physicalPath))
  1232. continue;
  1233. if (!files.Contains (physicalPath))
  1234. files.Add (physicalPath);
  1235. }
  1236. }
  1237. dep = new CacheDependency (files.ToArray ());
  1238. } else
  1239. dep = null;
  1240. HttpRuntime.InternalCache.Add (BUILD_MANAGER_VIRTUAL_PATH_CACHE_PREFIX + virtualPath,
  1241. true,
  1242. dep,
  1243. Cache.NoAbsoluteExpiration,
  1244. Cache.NoSlidingExpiration,
  1245. CacheItemPriority.High,
  1246. new CacheItemRemovedCallback (OnVirtualPathChanged));
  1247. }
  1248. }
  1249. }