PageRenderTime 64ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/System.Web/System.Web.Compilation/BuildManager.cs

https://bitbucket.org/danipen/mono
C# | 1526 lines | 1209 code | 240 blank | 77 comment | 366 complexity | bc128a937edfd95319c7cb24af372d14 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // System.Web.Compilation.BuildManager
  3. //
  4. // Authors:
  5. // Chris Toshok (toshok@ximian.com)
  6. // Gonzalo Paniagua Javier (gonzalo@novell.com)
  7. // Marek Habersack (mhabersack@novell.com)
  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. string appVirtualRoot = VirtualPathUtility.AppendTrailingSlash (HttpRuntime.AppDomainAppVirtualPath);
  198. foreach (string vpath in precompiled.Keys) {
  199. parts = vpath.Split ('/');
  200. for (int i = 0; i < parts.Length; i++) {
  201. if (String.IsNullOrEmpty (parts [i]))
  202. continue;
  203. // The path must be rooted, otherwise PhysicalPath returned
  204. // below will be relative to the current request path and
  205. // File.Exists will return a false negative. See bug #546053
  206. string test_path = appVirtualRoot + String.Join ("/", parts, i, parts.Length - i);
  207. VirtualPath result = GetAbsoluteVirtualPath (test_path);
  208. if (result != null && File.Exists (result.PhysicalPath)) {
  209. skip = i - 1;
  210. break;
  211. }
  212. }
  213. }
  214. string app_vpath = HttpRuntime.AppDomainAppVirtualPath;
  215. if (skip == -1 || (skip == 0 && app_vpath == "/"))
  216. return;
  217. if (!app_vpath.EndsWith ("/"))
  218. app_vpath = app_vpath + "/";
  219. Dictionary<string, PreCompilationData> copy = new Dictionary<string, PreCompilationData> (precompiled);
  220. precompiled.Clear ();
  221. foreach (KeyValuePair<string,PreCompilationData> entry in copy) {
  222. parts = entry.Key.Split ('/');
  223. string new_path;
  224. if (String.IsNullOrEmpty (parts [0]))
  225. new_path = app_vpath + String.Join ("/", parts, skip + 1, parts.Length - skip - 1);
  226. else
  227. new_path = app_vpath + String.Join ("/", parts, skip, parts.Length - skip);
  228. entry.Value.VirtualPath = new_path;
  229. precompiled.Add (new_path, entry.Value);
  230. }
  231. }
  232. static bool LoadPrecompilationInfo (string precomp_config)
  233. {
  234. using (XmlTextReader reader = new XmlTextReader (precomp_config)) {
  235. reader.MoveToContent ();
  236. if (reader.Name != "precompiledApp")
  237. return false;
  238. /* unused
  239. if (reader.HasAttributes)
  240. while (reader.MoveToNextAttribute ())
  241. if (reader.Name == "updatable") {
  242. updatable = (reader.Value == "true");
  243. break;
  244. }
  245. */
  246. }
  247. string [] compiled = Directory.GetFiles (HttpRuntime.BinDirectory, "*.compiled");
  248. foreach (string str in compiled)
  249. LoadCompiled (str);
  250. FixVirtualPaths ();
  251. return true;
  252. }
  253. static void LoadCompiled (string filename)
  254. {
  255. using (XmlTextReader reader = new XmlTextReader (filename)) {
  256. reader.MoveToContent ();
  257. if (reader.Name == "preserve" && reader.HasAttributes) {
  258. reader.MoveToNextAttribute ();
  259. string val = reader.Value;
  260. // 1 -> app_code subfolder - add the assembly to CodeAssemblies
  261. // 2 -> ashx
  262. // 3 -> ascx, aspx
  263. // 6 -> app_code - add the assembly to CodeAssemblies
  264. // 8 -> global.asax
  265. // 9 -> App_GlobalResources - set the assembly for HttpContext
  266. if (reader.Name == "resultType" && (val == "2" || val == "3" || val == "8"))
  267. LoadPageData (reader, true);
  268. else if (val == "1" || val == "6") {
  269. PreCompilationData pd = LoadPageData (reader, false);
  270. CodeAssemblies.Add (Assembly.Load (pd.AssemblyFileName));
  271. } else if (val == "9") {
  272. PreCompilationData pd = LoadPageData (reader, false);
  273. HttpContext.AppGlobalResourcesAssembly = Assembly.Load (pd.AssemblyFileName);
  274. }
  275. }
  276. }
  277. }
  278. class PreCompilationData {
  279. public string VirtualPath;
  280. public string AssemblyFileName;
  281. public string TypeName;
  282. public Type Type;
  283. }
  284. static PreCompilationData LoadPageData (XmlTextReader reader, bool store)
  285. {
  286. PreCompilationData pc_data = new PreCompilationData ();
  287. while (reader.MoveToNextAttribute ()) {
  288. string name = reader.Name;
  289. if (name == "virtualPath")
  290. pc_data.VirtualPath = VirtualPathUtility.RemoveTrailingSlash (reader.Value);
  291. else if (name == "assembly")
  292. pc_data.AssemblyFileName = reader.Value;
  293. else if (name == "type")
  294. pc_data.TypeName = reader.Value;
  295. }
  296. if (store) {
  297. if (precompiled == null)
  298. precompiled = new Dictionary<string, PreCompilationData> (RuntimeHelpers.StringEqualityComparerCulture);
  299. precompiled.Add (pc_data.VirtualPath, pc_data);
  300. }
  301. return pc_data;
  302. }
  303. static void AddAssembly (Assembly asm, List <Assembly> al)
  304. {
  305. if (al.Contains (asm))
  306. return;
  307. al.Add (asm);
  308. }
  309. static void AddPathToIgnore (string vp)
  310. {
  311. if (virtualPathsToIgnore == null)
  312. virtualPathsToIgnore = new Dictionary <string, bool> (RuntimeHelpers.StringEqualityComparerCulture);
  313. VirtualPath path = GetAbsoluteVirtualPath (vp);
  314. string vpAbsolute = path.Absolute;
  315. if (!virtualPathsToIgnore.ContainsKey (vpAbsolute)) {
  316. virtualPathsToIgnore.Add (vpAbsolute, true);
  317. haveVirtualPathsToIgnore = true;
  318. }
  319. string vpRelative = path.AppRelative;
  320. if (!virtualPathsToIgnore.ContainsKey (vpRelative)) {
  321. virtualPathsToIgnore.Add (vpRelative, true);
  322. haveVirtualPathsToIgnore = true;
  323. }
  324. if (!virtualPathsToIgnore.ContainsKey (vp)) {
  325. virtualPathsToIgnore.Add (vp, true);
  326. haveVirtualPathsToIgnore = true;
  327. }
  328. }
  329. internal static void AddToReferencedAssemblies (Assembly asm)
  330. {
  331. // should not be used
  332. }
  333. static void AssertVirtualPathExists (VirtualPath virtualPath)
  334. {
  335. string realpath;
  336. bool dothrow = false;
  337. if (virtualPath.IsFake) {
  338. realpath = virtualPath.PhysicalPath;
  339. if (!File.Exists (realpath) && !Directory.Exists (realpath))
  340. dothrow = true;
  341. } else {
  342. VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
  343. string vpAbsolute = virtualPath.Absolute;
  344. if (!vpp.FileExists (vpAbsolute) && !vpp.DirectoryExists (vpAbsolute))
  345. dothrow = true;
  346. }
  347. if (dothrow)
  348. throw new HttpException (404, "The file '" + virtualPath + "' does not exist.", virtualPath.Absolute);
  349. }
  350. static void Build (VirtualPath vp)
  351. {
  352. AssertVirtualPathExists (vp);
  353. CompilationSection cs = CompilationConfig;
  354. lock (bigCompilationLock) {
  355. bool entryExists;
  356. if (HasCachedItemNoLock (vp.Absolute, out entryExists))
  357. return;
  358. if (recursionDepth == 0)
  359. referencedAssemblies.Clear ();
  360. recursionDepth++;
  361. try {
  362. BuildInner (vp, cs != null ? cs.Debug : false);
  363. if (entryExists && recursionDepth <= 1)
  364. // We count only update builds - first time a file
  365. // (or a batch) is built doesn't count.
  366. buildCount++;
  367. } finally {
  368. // See http://support.microsoft.com/kb/319947
  369. if (buildCount > cs.NumRecompilesBeforeAppRestart)
  370. HttpRuntime.UnloadAppDomain ();
  371. recursionDepth--;
  372. }
  373. }
  374. }
  375. // This method assumes it is being called with the big compilation lock held
  376. static void BuildInner (VirtualPath vp, bool debug)
  377. {
  378. var builder = new BuildManagerDirectoryBuilder (vp);
  379. bool recursive = recursionDepth > 1;
  380. List <BuildProviderGroup> builderGroups = builder.Build (IsSingleBuild (vp, recursive));
  381. if (builderGroups == null)
  382. return;
  383. string vpabsolute = vp.Absolute;
  384. int buildHash = (vpabsolute.GetHashCode () | (int)DateTime.Now.Ticks) + (int)recursionDepth;
  385. string assemblyBaseName;
  386. AssemblyBuilder abuilder;
  387. CompilerType ct;
  388. int attempts;
  389. bool singleBuild, needMainVpBuild;
  390. CompilationException compilationError;
  391. // Each group becomes a separate assembly.
  392. foreach (BuildProviderGroup group in builderGroups) {
  393. needMainVpBuild = false;
  394. compilationError = null;
  395. assemblyBaseName = null;
  396. if (group.Count == 1) {
  397. if (recursive || !group.Master)
  398. assemblyBaseName = String.Format ("{0}_{1}.{2:x}.", group.NamePrefix, VirtualPathUtility.GetFileName (group [0].VirtualPath), buildHash);
  399. singleBuild = true;
  400. } else
  401. singleBuild = false;
  402. if (assemblyBaseName == null)
  403. assemblyBaseName = group.NamePrefix + "_";
  404. ct = group.CompilerType;
  405. attempts = 3;
  406. while (attempts > 0) {
  407. abuilder = new AssemblyBuilder (vp, CreateDomProvider (ct), assemblyBaseName);
  408. abuilder.CompilerOptions = ct.CompilerParameters;
  409. abuilder.AddAssemblyReference (GetReferencedAssemblies () as List <Assembly>);
  410. try {
  411. GenerateAssembly (abuilder, group, vp, debug);
  412. attempts = 0;
  413. } catch (CompilationException ex) {
  414. attempts--;
  415. if (singleBuild)
  416. throw new HttpException ("Single file build failed.", ex);
  417. if (attempts == 0) {
  418. needMainVpBuild = true;
  419. compilationError = ex;
  420. break;
  421. }
  422. CompilerResults results = ex.Results;
  423. if (results == null)
  424. throw new HttpException ("No results returned from failed compilation.", ex);
  425. else
  426. RemoveFailedAssemblies (vpabsolute, ex, abuilder, group, results, debug);
  427. }
  428. }
  429. if (needMainVpBuild) {
  430. // One last attempt - try to build just the requested path
  431. // if it's not built yet or just return without throwing the
  432. // exception if it has already been built.
  433. if (HasCachedItemNoLock (vpabsolute)) {
  434. if (debug)
  435. DescribeCompilationError ("Path '{0}' built successfully, but a compilation exception has been thrown for other files:",
  436. compilationError, vpabsolute);
  437. return;
  438. };
  439. // This will trigger a recursive build of the requested vp,
  440. // which means only the vp alone will be built (or not);
  441. Build (vp);
  442. if (HasCachedItemNoLock (vpabsolute)) {
  443. if (debug)
  444. DescribeCompilationError ("Path '{0}' built successfully, but a compilation exception has been thrown for other files:",
  445. compilationError, vpabsolute);
  446. return;
  447. }
  448. // In theory this code is unreachable. If the recursive
  449. // build of the main vp failed, then it should have thrown
  450. // the build exception.
  451. throw new HttpException ("Requested virtual path build failed.", compilationError);
  452. }
  453. }
  454. }
  455. static CodeDomProvider CreateDomProvider (CompilerType ct)
  456. {
  457. if (codeDomProviders == null)
  458. codeDomProviders = new Dictionary <Type, CodeDomProvider> ();
  459. Type type = ct.CodeDomProviderType;
  460. if (type == null) {
  461. CompilationSection cs = CompilationConfig;
  462. CompilerType tmp = GetDefaultCompilerTypeForLanguage (cs.DefaultLanguage, cs);
  463. if (tmp != null)
  464. type = tmp.CodeDomProviderType;
  465. }
  466. if (type == null)
  467. return null;
  468. CodeDomProvider ret;
  469. if (codeDomProviders.TryGetValue (type, out ret))
  470. return ret;
  471. ret = Activator.CreateInstance (type) as CodeDomProvider;
  472. if (ret == null)
  473. return null;
  474. codeDomProviders.Add (type, ret);
  475. return ret;
  476. }
  477. #if NET_4_0
  478. internal static void CallPreStartMethods ()
  479. {
  480. if (preStartMethodsDone)
  481. return;
  482. preStartMethodsRunning = true;
  483. MethodInfo mi = null;
  484. try {
  485. List <MethodInfo> methods = LoadPreStartMethodsFromAssemblies (GetReferencedAssemblies () as List <Assembly>);
  486. if (methods == null || methods.Count == 0)
  487. return;
  488. foreach (MethodInfo m in methods) {
  489. mi = m;
  490. m.Invoke (null, null);
  491. }
  492. } catch (Exception ex) {
  493. throw new HttpException (
  494. String.Format ("The pre-application start initialization method {0} on type {1} threw an exception with the following error message: {2}",
  495. mi != null ? mi.Name : "UNKNOWN",
  496. mi != null ? mi.DeclaringType.FullName : "UNKNOWN",
  497. ex.Message),
  498. ex
  499. );
  500. } finally {
  501. preStartMethodsRunning = false;
  502. preStartMethodsDone = true;
  503. }
  504. }
  505. static List <MethodInfo> LoadPreStartMethodsFromAssemblies (List <Assembly> assemblies)
  506. {
  507. if (assemblies == null || assemblies.Count == 0)
  508. return null;
  509. var ret = new List <MethodInfo> ();
  510. object[] attributes;
  511. Type type;
  512. PreApplicationStartMethodAttribute attr;
  513. foreach (Assembly asm in assemblies) {
  514. try {
  515. attributes = asm.GetCustomAttributes (typeof (PreApplicationStartMethodAttribute), false);
  516. if (attributes == null || attributes.Length == 0)
  517. continue;
  518. attr = attributes [0] as PreApplicationStartMethodAttribute;
  519. type = attr.Type;
  520. if (type == null)
  521. continue;
  522. } catch {
  523. continue;
  524. }
  525. MethodInfo mi;
  526. Exception error = null;
  527. try {
  528. if (type.IsPublic)
  529. mi = type.GetMethod (attr.MethodName, BindingFlags.Static | BindingFlags.Public, null, new Type[] {}, null);
  530. else
  531. mi = null;
  532. } catch (Exception ex) {
  533. error = ex;
  534. mi = null;
  535. }
  536. if (mi == null)
  537. throw new HttpException (
  538. String.Format (
  539. "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).",
  540. asm.FullName,
  541. type.FullName,
  542. attr.MethodName),
  543. error
  544. );
  545. ret.Add (mi);
  546. }
  547. return ret;
  548. }
  549. public static Type GetGlobalAsaxType ()
  550. {
  551. Type ret = HttpApplicationFactory.AppType;
  552. if (ret == null)
  553. return typeof (HttpApplication);
  554. return ret;
  555. }
  556. public static Stream CreateCachedFile (string fileName)
  557. {
  558. if (fileName != null && (fileName == String.Empty || fileName.IndexOf (Path.DirectorySeparatorChar) != -1))
  559. throw new ArgumentException ("Value does not fall within the expected range.");
  560. string path = Path.Combine (HttpRuntime.CodegenDir, fileName);
  561. return new FileStream (path, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
  562. }
  563. public static Stream ReadCachedFile (string fileName)
  564. {
  565. if (fileName != null && (fileName == String.Empty || fileName.IndexOf (Path.DirectorySeparatorChar) != -1))
  566. throw new ArgumentException ("Value does not fall within the expected range.");
  567. string path = Path.Combine (HttpRuntime.CodegenDir, fileName);
  568. if (!File.Exists (path))
  569. return null;
  570. return new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.None);
  571. }
  572. [MonoDocumentationNote ("Fully implemented but no info on application pre-init stage is available yet.")]
  573. public static void AddReferencedAssembly (Assembly assembly)
  574. {
  575. if (assembly == null)
  576. throw new ArgumentNullException ("assembly");
  577. if (preStartMethodsDone)
  578. throw new InvalidOperationException ("This method cannot be called after the application's pre-start initialization stage.");
  579. if (dynamicallyRegisteredAssemblies == null)
  580. dynamicallyRegisteredAssemblies = new List <Assembly> ();
  581. if (!dynamicallyRegisteredAssemblies.Contains (assembly))
  582. dynamicallyRegisteredAssemblies.Add (assembly);
  583. }
  584. [MonoDocumentationNote ("Not used by Mono internally. Needed for MVC3")]
  585. public static IWebObjectFactory GetObjectFactory (string virtualPath, bool throwIfNotFound)
  586. {
  587. if (CompilingTopLevelAssemblies)
  588. throw new HttpException ("Method must not be called while compiling the top level assemblies.");
  589. Type type;
  590. if (is_precompiled) {
  591. type = GetPrecompiledType (virtualPath);
  592. if (type == null) {
  593. if (throwIfNotFound)
  594. throw new HttpException (String.Format ("Virtual path '{0}' not found in precompiled application type cache.", virtualPath));
  595. else
  596. return null;
  597. }
  598. return new SimpleWebObjectFactory (type);
  599. }
  600. Exception compileException = null;
  601. try {
  602. type = GetCompiledType (virtualPath);
  603. } catch (Exception ex) {
  604. compileException = ex;
  605. type = null;
  606. }
  607. if (type == null) {
  608. if (throwIfNotFound)
  609. throw new HttpException (String.Format ("Virtual path '{0}' does not exist.", virtualPath), compileException);
  610. return null;
  611. }
  612. return new SimpleWebObjectFactory (type);
  613. }
  614. #endif
  615. public static object CreateInstanceFromVirtualPath (string virtualPath, Type requiredBaseType)
  616. {
  617. return CreateInstanceFromVirtualPath (GetAbsoluteVirtualPath (virtualPath), requiredBaseType);
  618. }
  619. internal static object CreateInstanceFromVirtualPath (VirtualPath virtualPath, Type requiredBaseType)
  620. {
  621. if (requiredBaseType == null)
  622. throw new NullReferenceException (); // This is what MS does, but
  623. // from somewhere else.
  624. Type type = GetCompiledType (virtualPath);
  625. if (type == null)
  626. return null;
  627. if (!requiredBaseType.IsAssignableFrom (type))
  628. throw new HttpException (500,
  629. String.Format ("Type '{0}' does not inherit from '{1}'.", type.FullName, requiredBaseType.FullName));
  630. return Activator.CreateInstance (type, null);
  631. }
  632. static void DescribeCompilationError (string format, CompilationException ex, params object[] parms)
  633. {
  634. StringBuilder sb = new StringBuilder ();
  635. string newline = Environment.NewLine;
  636. if (parms != null)
  637. sb.AppendFormat (format + newline, parms);
  638. else
  639. sb.Append (format + newline);
  640. CompilerResults results = ex != null ? ex.Results : null;
  641. if (results == null)
  642. sb.Append ("No compiler error information present." + newline);
  643. else {
  644. sb.Append ("Compiler errors:" + newline);
  645. foreach (CompilerError error in results.Errors)
  646. sb.Append (" " + error.ToString () + newline);
  647. }
  648. if (ex != null) {
  649. sb.Append (newline + "Exception thrown:" + newline);
  650. sb.Append (ex.ToString ());
  651. }
  652. ShowDebugModeMessage (sb.ToString ());
  653. }
  654. static BuildProvider FindBuildProviderForPhysicalPath (string path, BuildProviderGroup group, HttpRequest req)
  655. {
  656. if (req == null || String.IsNullOrEmpty (path))
  657. return null;
  658. foreach (BuildProvider bp in group) {
  659. if (String.Compare (path, req.MapPath (bp.VirtualPath), RuntimeHelpers.StringComparison) == 0)
  660. return bp;
  661. }
  662. return null;
  663. }
  664. static void GenerateAssembly (AssemblyBuilder abuilder, BuildProviderGroup group, VirtualPath vp, bool debug)
  665. {
  666. IDictionary <string, bool> deps;
  667. BuildManagerCacheItem bmci;
  668. string bvp, vpabsolute = vp.Absolute;
  669. StringBuilder sb;
  670. string newline;
  671. int failedCount = 0;
  672. if (debug) {
  673. newline = Environment.NewLine;
  674. sb = new StringBuilder ("Code generation for certain virtual paths in a batch failed. Those files have been removed from the batch." + newline);
  675. sb.Append ("Since you're running in debug mode, here's some more information about the error:" + newline);
  676. } else {
  677. newline = null;
  678. sb = null;
  679. }
  680. List <BuildProvider> failedBuildProviders = null;
  681. StringComparison stringComparison = RuntimeHelpers.StringComparison;
  682. foreach (BuildProvider bp in group) {
  683. bvp = bp.VirtualPath;
  684. if (HasCachedItemNoLock (bvp))
  685. continue;
  686. try {
  687. bp.GenerateCode (abuilder);
  688. } catch (Exception ex) {
  689. if (String.Compare (bvp, vpabsolute, stringComparison) == 0) {
  690. if (ex is CompilationException || ex is ParseException)
  691. throw;
  692. throw new HttpException ("Code generation failed.", ex);
  693. }
  694. if (failedBuildProviders == null)
  695. failedBuildProviders = new List <BuildProvider> ();
  696. failedBuildProviders.Add (bp);
  697. failedCount++;
  698. if (sb != null) {
  699. if (failedCount > 1)
  700. sb.Append (newline);
  701. sb.AppendFormat ("Failed file virtual path: {0}; Exception: {1}{2}{1}", bp.VirtualPath, newline, ex);
  702. }
  703. continue;
  704. }
  705. deps = bp.ExtractDependencies ();
  706. if (deps != null) {
  707. foreach (var dep in deps) {
  708. bmci = GetCachedItemNoLock (dep.Key);
  709. if (bmci == null || bmci.BuiltAssembly == null)
  710. continue;
  711. abuilder.AddAssemblyReference (bmci.BuiltAssembly);
  712. }
  713. }
  714. }
  715. if (sb != null && failedCount > 0)
  716. ShowDebugModeMessage (sb.ToString ());
  717. if (failedBuildProviders != null) {
  718. foreach (BuildProvider bp in failedBuildProviders)
  719. group.Remove (bp);
  720. }
  721. foreach (Assembly asm in referencedAssemblies) {
  722. if (asm == null)
  723. continue;
  724. abuilder.AddAssemblyReference (asm);
  725. }
  726. CompilerResults results = abuilder.BuildAssembly (vp);
  727. // No results is not an error - it is possible that the assembly builder contained only .asmx and
  728. // .ashx files which had no body, just the directive. In such case, no code unit or code file is added
  729. // to the assembly builder and, in effect, no assembly is produced but there are STILL types that need
  730. // to be added to the cache.
  731. Assembly compiledAssembly = results != null ? results.CompiledAssembly : null;
  732. try {
  733. #if SYSTEMCORE_DEP
  734. buildCacheLock.EnterWriteLock ();
  735. #else
  736. buildCacheLock.AcquireWriterLock (-1);
  737. #endif
  738. if (compiledAssembly != null)
  739. referencedAssemblies.Add (compiledAssembly);
  740. foreach (BuildProvider bp in group) {
  741. if (HasCachedItemNoLock (bp.VirtualPath))
  742. continue;
  743. StoreInCache (bp, compiledAssembly, results);
  744. }
  745. } finally {
  746. #if SYSTEMCORE_DEP
  747. buildCacheLock.ExitWriteLock ();
  748. #else
  749. buildCacheLock.ReleaseWriterLock ();
  750. #endif
  751. }
  752. }
  753. static VirtualPath GetAbsoluteVirtualPath (string virtualPath)
  754. {
  755. string vp;
  756. if (!VirtualPathUtility.IsRooted (virtualPath)) {
  757. HttpContext ctx = HttpContext.Current;
  758. HttpRequest req = ctx != null ? ctx.Request : null;
  759. if (req != null) {
  760. string fileDir = req.FilePath;
  761. if (!String.IsNullOrEmpty (fileDir) && String.Compare (fileDir, "/", StringComparison.Ordinal) != 0)
  762. fileDir = VirtualPathUtility.GetDirectory (fileDir);
  763. else
  764. fileDir = "/";
  765. vp = VirtualPathUtility.Combine (fileDir, virtualPath);
  766. } else
  767. throw new HttpException ("No context, cannot map paths.");
  768. } else
  769. vp = virtualPath;
  770. return new VirtualPath (vp);
  771. }
  772. [MonoTODO ("Not implemented, always returns null")]
  773. public static BuildDependencySet GetCachedBuildDependencySet (HttpContext context, string virtualPath)
  774. {
  775. return null; // null is ok here until we store the dependency set in the Cache.
  776. }
  777. #if NET_4_0
  778. [MonoTODO ("Not implemented, always returns null")]
  779. public static BuildDependencySet GetCachedBuildDependencySet (HttpContext context, string virtualPath, bool ensureIsUpToDate)
  780. {
  781. return null; // null is ok here until we store the dependency set in the Cache.
  782. }
  783. #endif
  784. static BuildManagerCacheItem GetCachedItem (string vp)
  785. {
  786. try {
  787. #if SYSTEMCORE_DEP
  788. buildCacheLock.EnterReadLock ();
  789. #else
  790. buildCacheLock.AcquireReaderLock (-1);
  791. #endif
  792. return GetCachedItemNoLock (vp);
  793. } finally {
  794. #if SYSTEMCORE_DEP
  795. buildCacheLock.ExitReadLock ();
  796. #else
  797. buildCacheLock.ReleaseReaderLock ();
  798. #endif
  799. }
  800. }
  801. static BuildManagerCacheItem GetCachedItemNoLock (string vp)
  802. {
  803. BuildManagerCacheItem ret;
  804. if (buildCache.TryGetValue (vp, out ret))
  805. return ret;
  806. return null;
  807. }
  808. internal static Type GetCodeDomProviderType (BuildProvider provider)
  809. {
  810. CompilerType codeCompilerType;
  811. Type codeDomProviderType = null;
  812. codeCompilerType = provider.CodeCompilerType;
  813. if (codeCompilerType != null)
  814. codeDomProviderType = codeCompilerType.CodeDomProviderType;
  815. if (codeDomProviderType == null)
  816. throw new HttpException (String.Concat ("Provider '", provider, " 'fails to specify the compiler type."));
  817. return codeDomProviderType;
  818. }
  819. static Type GetPrecompiledType (string virtualPath)
  820. {
  821. if (precompiled == null || precompiled.Count == 0)
  822. return null;
  823. PreCompilationData pc_data;
  824. var vp = new VirtualPath (virtualPath);
  825. if (!precompiled.TryGetValue (vp.Absolute, out pc_data))
  826. if (!precompiled.TryGetValue (virtualPath, out pc_data))
  827. return null;
  828. if (pc_data.Type == null)
  829. pc_data.Type = Type.GetType (pc_data.TypeName + ", " + pc_data.AssemblyFileName, true);
  830. return pc_data.Type;
  831. }
  832. internal static Type GetPrecompiledApplicationType ()
  833. {
  834. if (!is_precompiled)
  835. return null;
  836. string appVp = VirtualPathUtility.AppendTrailingSlash (HttpRuntime.AppDomainAppVirtualPath);
  837. Type apptype = GetPrecompiledType (VirtualPathUtility.Combine (appVp, "global.asax"));
  838. if (apptype == null)
  839. apptype = GetPrecompiledType (VirtualPathUtility.Combine (appVp, "Global.asax"));
  840. return apptype;
  841. }
  842. public static Assembly GetCompiledAssembly (string virtualPath)
  843. {
  844. return GetCompiledAssembly (GetAbsoluteVirtualPath (virtualPath));
  845. }
  846. internal static Assembly GetCompiledAssembly (VirtualPath virtualPath)
  847. {
  848. string vpabsolute = virtualPath.Absolute;
  849. if (is_precompiled) {
  850. Type type = GetPrecompiledType (vpabsolute);
  851. if (type != null)
  852. return type.Assembly;
  853. }
  854. BuildManagerCacheItem bmci = GetCachedItem (vpabsolute);
  855. if (bmci != null)
  856. return bmci.BuiltAssembly;
  857. Build (virtualPath);
  858. bmci = GetCachedItem (vpabsolute);
  859. if (bmci != null)
  860. return bmci.BuiltAssembly;
  861. return null;
  862. }
  863. public static Type GetCompiledType (string virtualPath)
  864. {
  865. return GetCompiledType (GetAbsoluteVirtualPath (virtualPath));
  866. }
  867. internal static Type GetCompiledType (VirtualPath virtualPath)
  868. {
  869. string vpabsolute = virtualPath.Absolute;
  870. if (is_precompiled) {
  871. Type type = GetPrecompiledType (vpabsolute);
  872. if (type != null)
  873. return type;
  874. }
  875. BuildManagerCacheItem bmci = GetCachedItem (vpabsolute);
  876. if (bmci != null) {
  877. ReferenceAssemblyInCompilation (bmci);
  878. return bmci.Type;
  879. }
  880. Build (virtualPath);
  881. bmci = GetCachedItem (vpabsolute);
  882. if (bmci != null) {
  883. ReferenceAssemblyInCompilation (bmci);
  884. return bmci.Type;
  885. }
  886. return null;
  887. }
  888. public static string GetCompiledCustomString (string virtualPath)
  889. {
  890. return GetCompiledCustomString (GetAbsoluteVirtualPath (virtualPath));
  891. }
  892. internal static string GetCompiledCustomString (VirtualPath virtualPath)
  893. {
  894. string vpabsolute = virtualPath.Absolute;
  895. BuildManagerCacheItem bmci = GetCachedItem (vpabsolute);
  896. if (bmci != null)
  897. return bmci.CompiledCustomString;
  898. Build (virtualPath);
  899. bmci = GetCachedItem (vpabsolute);
  900. if (bmci != null)
  901. return bmci.CompiledCustomString;
  902. return null;
  903. }
  904. internal static CompilerType GetDefaultCompilerTypeForLanguage (string language, CompilationSection configSection)
  905. {
  906. return GetDefaultCompilerTypeForLanguage (language, configSection, true);
  907. }
  908. internal static CompilerType GetDefaultCompilerTypeForLanguage (string language, CompilationSection configSection, bool throwOnMissing)
  909. {
  910. // MS throws when accesing a Hashtable, we do here.
  911. if (language == null || language.Length == 0)
  912. throw new ArgumentNullException ("language");
  913. CompilationSection config;
  914. if (configSection == null)
  915. config = WebConfigurationManager.GetWebApplicationSection ("system.web/compilation") as CompilationSection;
  916. else
  917. config = configSection;
  918. Compiler compiler = config.Compilers.Get (language);
  919. CompilerParameters p;
  920. Type type;
  921. if (compiler != null) {
  922. type = HttpApplication.LoadType (compiler.Type, true);
  923. p = new CompilerParameters ();
  924. p.CompilerOptions = compiler.CompilerOptions;
  925. p.WarningLevel = compiler.WarningLevel;
  926. SetCommonParameters (config, p, type, language);
  927. return new CompilerType (type, p);
  928. }
  929. if (CodeDomProvider.IsDefinedLanguage (language)) {
  930. CompilerInfo info = CodeDomProvider.GetCompilerInfo (language);
  931. p = info.CreateDefaultCompilerParameters ();
  932. type = info.CodeDomProviderType;
  933. SetCommonParameters (config, p, type, language);
  934. return new CompilerType (type, p);
  935. }
  936. if (throwOnMissing)
  937. throw new HttpException (String.Concat ("No compiler for language '", language, "'."));
  938. return null;
  939. }
  940. public static ICollection GetReferencedAssemblies ()
  941. {
  942. if (getReferencedAssembliesInvoked)
  943. return configReferencedAssemblies;
  944. if (allowReferencedAssembliesCaching)
  945. getReferencedAssembliesInvoked = true;
  946. if (configReferencedAssemblies == null)
  947. configReferencedAssemblies = new List <Assembly> ();
  948. else if (getReferencedAssembliesInvoked)
  949. configReferencedAssemblies.Clear ();
  950. CompilationSection compConfig = WebConfigurationManager.GetWebApplicationSection ("system.web/compilation") as CompilationSection;
  951. if (compConfig == null)
  952. return configReferencedAssemblies;
  953. bool addAssembliesInBin = false;
  954. foreach (AssemblyInfo info in compConfig.Assemblies) {
  955. if (info.Assembly == "*")
  956. addAssembliesInBin = is_precompiled ? false : true;
  957. else
  958. LoadAssembly (info, configReferencedAssemblies);
  959. }
  960. foreach (Assembly topLevelAssembly in TopLevelAssemblies)
  961. configReferencedAssemblies.Add (topLevelAssembly);
  962. foreach (string assLocation in WebConfigurationManager.ExtraAssemblies)
  963. LoadAssembly (assLocation, configReferencedAssemblies);
  964. #if NET_4_0
  965. if (dynamicallyRegisteredAssemblies != null)
  966. foreach (Assembly registeredAssembly in dynamicallyRegisteredAssemblies)
  967. configReferencedAssemblies.Add (registeredAssembly);
  968. #endif
  969. // Precompiled sites unconditionally load all assemblies from bin/ (fix for
  970. // bug #502016)
  971. if (is_precompiled || addAssembliesInBin) {
  972. foreach (string s in HttpApplication.BinDirectoryAssemblies) {
  973. try {
  974. LoadAssembly (s, configReferencedAssemblies);
  975. } catch (BadImageFormatException) {
  976. // ignore silently
  977. }
  978. }
  979. }
  980. return configReferencedAssemblies;
  981. }
  982. // The 2 GetType() overloads work on the global.asax, App_GlobalResources, App_WebReferences or App_Browsers
  983. public static Type GetType (string typeName, bool throwOnError)
  984. {
  985. return GetType (typeName, throwOnError, false);
  986. }
  987. public static Type GetType (string typeName, bool throwOnError, bool ignoreCase)
  988. {
  989. if (String.IsNullOrEmpty (typeName))
  990. throw new HttpException ("Type name must not be empty.");
  991. Type ret = null;
  992. Exception ex = null;
  993. try {
  994. string wantedAsmName;
  995. string wantedTypeName;
  996. int comma = typeName.IndexOf (',');
  997. if (comma > 0 && comma < typeName.Length - 1) {
  998. var aname = new AssemblyName (typeName.Substring (comma + 1));
  999. wantedAsmName = aname.ToString ();
  1000. wantedTypeName = typeName.Substring (0, comma);
  1001. } else {
  1002. wantedAsmName = null;
  1003. wantedTypeName = typeName;
  1004. }
  1005. var assemblies = new List <Assembly> ();
  1006. assemblies.AddRange (BuildManager.GetReferencedAssemblies () as List <Assembly>);
  1007. assemblies.AddRange (TopLevel_Assemblies);
  1008. Type appType = HttpApplicationFactory.AppType;
  1009. if (appType != null)
  1010. assemblies.Add (appType.Assembly);
  1011. foreach (Assembly asm in assemblies) {
  1012. if (asm == null)
  1013. continue;
  1014. if (wantedAsmName != null) {
  1015. // So dumb...
  1016. if (String.Compare (wantedAsmName, asm.GetName ().ToString (), StringComparison.Ordinal) == 0) {
  1017. ret = asm.GetType (wantedTypeName, throwOnError, ignoreCase);
  1018. if (ret != null)
  1019. return ret;
  1020. }
  1021. continue;
  1022. }
  1023. ret = asm.GetType (wantedTypeName, false, ignoreCase);
  1024. if (ret != null)
  1025. return ret;
  1026. }
  1027. } catch (Exception e) {
  1028. ex = e;
  1029. }
  1030. if (throwOnError)
  1031. throw new HttpException ("Failed to find the specified type.", ex);
  1032. return null;
  1033. }
  1034. public static ICollection GetVirtualPathDependencies (string virtualPath)
  1035. {
  1036. return GetVirtualPathDependencies (virtualPath, null);
  1037. }
  1038. internal static ICollection GetVirtualPathDependencies (string virtualPath, BuildProvider bprovider)
  1039. {
  1040. BuildProvider provider = bprovider;
  1041. if (provider == null) {
  1042. CompilationSection cs = CompilationConfig;
  1043. if (cs == null)
  1044. return null;
  1045. provider = BuildManagerDirectoryBuilder.GetBuildProvider (virtualPath, cs.BuildProviders);
  1046. }
  1047. if (provider == null)
  1048. return null;
  1049. IDictionary <string, bool> deps = provider.ExtractDependencies ();
  1050. if (deps == null)
  1051. return null;
  1052. return (ICollection)deps.Keys;
  1053. }
  1054. internal static bool HasCachedItemNoLock (string vp, out bool entryExists)
  1055. {
  1056. BuildManagerCacheItem item;
  1057. if (buildCache.TryGetValue (vp, out item)) {
  1058. entryExists = true;
  1059. return item != null;
  1060. }
  1061. entryExists = false;
  1062. return false;
  1063. }
  1064. internal static bool HasCachedItemNoLock (string vp)
  1065. {
  1066. bool dummy;
  1067. return HasCachedItemNoLock (vp, out dummy);
  1068. }
  1069. internal static bool IgnoreVirtualPath (string virtualPath)
  1070. {
  1071. if (!virtualPathsToIgnoreChecked) {
  1072. lock (virtualPathsToIgnoreLock) {
  1073. if (!virtualPathsToIgnoreChecked)
  1074. LoadVirtualPathsToIgnore ();
  1075. virtualPathsToIgnoreChecked = true;
  1076. }
  1077. }
  1078. if (!haveVirtualPathsToIgnore)
  1079. return false;
  1080. if (virtualPathsToIgnore.ContainsKey (virtualPath))
  1081. return true;
  1082. return false;
  1083. }
  1084. static bool IsSingleBuild (VirtualPath vp, bool recursive)
  1085. {
  1086. if (String.Compare (vp.AppRelative, "~/global.asax", StringComparison.OrdinalIgnoreCase) == 0)
  1087. return true;
  1088. if (!BatchMode)
  1089. return true;
  1090. return recursive;
  1091. }
  1092. static void LoadAssembly (string path, List <Assembly> al)
  1093. {
  1094. AddAssembly (Assembly.LoadFrom (path), al);
  1095. }
  1096. static void LoadAssembly (AssemblyInfo info, List <Assembly> al)
  1097. {
  1098. AddAssembly (Assembly.Load (info.Assembly), al);
  1099. }
  1100. static void LoadVirtualPathsToIgnore ()
  1101. {
  1102. NameValueCollection appSettings = WebConfigurationManager.AppSettings;
  1103. if (appSettings == null)
  1104. return;
  1105. string pathsFromConfig = appSettings ["MonoAspnetBatchCompileIgnorePaths"];
  1106. string pathsFromFile = appSettings ["MonoAspnetBatchCompileIgnoreFromFile"];
  1107. if (!String.IsNullOrEmpty (pathsFromConfig)) {
  1108. string[] paths = pathsFromConfig.Split (virtualPathsToIgnoreSplitChars);
  1109. string path;
  1110. foreach (string p in paths) {
  1111. path = p.Trim ();
  1112. if (path.Length == 0)
  1113. continue;
  1114. AddPathToIgnore (path);
  1115. }
  1116. }
  1117. if (!String.IsNullOrEmpty (pathsFromFile)) {
  1118. string realpath;
  1119. HttpContext ctx = HttpContext.Current;
  1120. HttpRequest req = ctx != null ? ctx.Request : null;
  1121. if (req == null)
  1122. throw new HttpException ("Missing context, cannot continue.");
  1123. realpath = req.MapPath (pathsFromFile);
  1124. if (!File.Exists (realpath))
  1125. return;
  1126. string[] paths = File.ReadAllLines (realpath);
  1127. if (paths == null || paths.Length == 0)
  1128. return;
  1129. string path;
  1130. foreach (string p in paths) {
  1131. path = p.Trim ();
  1132. if (path.Length == 0)
  1133. continue;
  1134. AddPathToIgnore (path);
  1135. }
  1136. }
  1137. }
  1138. static void OnEntryRemoved (string vp)
  1139. {
  1140. BuildManagerRemoveEntryEventHandler eh = events [buildManagerRemoveEntryEvent] as BuildManagerRemoveEntryEventHandler;
  1141. if (eh != null)
  1142. eh (new BuildManagerRemoveEntryEventArgs (vp, HttpContext.Current));
  1143. }
  1144. static void OnVirtualPathChanged (string key, object value, CacheItemRemovedReason removedReason)
  1145. {
  1146. string virtualPath;
  1147. if (StrUtils.StartsWith (key, BUILD_MANAGER_VIRTUAL_PATH_CACHE_PREFIX))
  1148. virtualPath = key.Substring (BUILD_MANAGER_VIRTUAL_PATH_CACHE_PREFIX_LENGTH);
  1149. else
  1150. return;
  1151. try {
  1152. #if SYSTEMCORE_DEP
  1153. buildCacheLock.EnterWriteLock ();
  1154. #else
  1155. buildCacheLock.AcquireWriterLock (-1);
  1156. #endif
  1157. if (HasCachedItemNoLock (virtualPath)) {
  1158. buildCache [virtualPath] = null;
  1159. OnEntryRemoved (virtualPath);
  1160. }
  1161. } finally {
  1162. #if SYSTEMCORE_DEP
  1163. buildCacheLock.ExitWriteLock ();
  1164. #else
  1165. buildCacheLock.ReleaseWriterLock ();
  1166. #endif
  1167. }
  1168. }
  1169. static void ReferenceAssemblyInCompilation (BuildManagerCacheItem bmci)
  1170. {
  1171. if (recursionDepth == 0 || referencedAssemblies.Contains (bmci.BuiltAssembly))
  1172. return;
  1173. referencedAssemblies.Add (bmci.BuiltAssembly);
  1174. }
  1175. static void RemoveFailedAssemblies (string requestedVirtualPath, CompilationException ex, AssemblyBuilder abuilder,
  1176. BuildProviderGroup group, CompilerResults results, bool debug)
  1177. {
  1178. StringBuilder sb;
  1179. string newline;
  1180. if (debug) {
  1181. newline = Environment.NewLine;
  1182. sb = new StringBuilder ("Compilation of certain files in a batch failed. Another attempt to compile the batch will be made." + newline);
  1183. sb.Append ("Since you're running in debug mode, here's some more information about the error:" + newline);
  1184. } else {
  1185. newline = null;
  1186. sb = null;
  1187. }
  1188. var failedBuildProviders = new List <BuildProvider> ();
  1189. BuildProvider bp;
  1190. HttpContext ctx = HttpContext.Current;
  1191. HttpRequest req = ctx != null ? ctx.Request : null;
  1192. bool rethrow = false;
  1193. foreach (CompilerError error in results.Errors) {
  1194. if (error.IsWarning)
  1195. continue;
  1196. bp = abuilder.GetBuildProviderForPhysicalFilePath (error.FileName);
  1197. if (bp == null) {
  1198. bp = FindBuildProviderForPhysicalPath (error.FileName, group, req);
  1199. if (bp == null)
  1200. continue;
  1201. }
  1202. if (String.Compare (bp.VirtualPath, requestedVirtualPath, StringComparison.Ordinal) == 0)
  1203. rethrow = true;
  1204. if (!failedBuildProviders.Contains (bp)) {
  1205. failedBuildProviders.Add (bp);
  1206. if (sb != null)
  1207. sb.AppendFormat ("\t{0}{1}", bp.VirtualPath, newline);
  1208. }
  1209. if (sb != null)
  1210. sb.AppendFormat ("\t\t{0}{1}", error, newline);
  1211. }
  1212. foreach (BuildProvider fbp in failedBuildProviders)
  1213. group.Remove (fbp);
  1214. if (sb != null) {
  1215. sb.AppendFormat ("{0}The following exception has been thrown for the file(s) listed above:{0}{1}",
  1216. newline, ex.ToString ());
  1217. ShowDebugModeMessage (sb.ToString ());
  1218. sb = null;
  1219. }
  1220. if (rethrow)
  1221. throw new HttpException ("Compilation failed.", ex);
  1222. }
  1223. static void SetCommonParameters (CompilationSection config, CompilerParameters p, Type compilerType, string language)
  1224. {
  1225. p.IncludeDebugInformation = config.Debug;
  1226. MonoSettingsSection mss = WebConfigurationManager.GetSection ("system.web/monoSettings") as MonoSettingsSection;
  1227. if (mss == null || !mss.UseCompilersCompatibility)
  1228. return;
  1229. Compiler compiler = mss.CompilersCompatibility.Get (language);
  1230. if (compiler == null)
  1231. return;
  1232. Type type = HttpApplication.LoadType (compiler.Type, false);
  1233. if (type != compilerType)
  1234. return;
  1235. p.CompilerOptions = String.Concat (p.CompilerOptions, " ", compiler.CompilerOptions);
  1236. }
  1237. static void ShowDebugModeMessage (string msg)
  1238. {
  1239. if (suppressDebugModeMessages)
  1240. return;
  1241. Console.Error.WriteLine ();
  1242. Console.Error.WriteLine ("******* DEBUG MODE MESSAGE *******");
  1243. Console.Error.WriteLine (msg);
  1244. Console.Error.WriteLine ("******* DEBUG MODE MESSAGE *******");
  1245. Console.Error.WriteLine ();
  1246. }
  1247. static void StoreInCache (BuildProvider bp, Assembly compiledAssembly, CompilerResults results)
  1248. {
  1249. string virtualPath = bp.VirtualPath;
  1250. var item = new BuildManagerCacheItem (compiledAssembly, bp, results);
  1251. if (buildCache.ContainsKey (virtualPath))
  1252. buildCache [virtualPath] = item;
  1253. else
  1254. buildCache.Add (virtualPath, item);
  1255. HttpContext ctx = HttpContext.Current;
  1256. HttpRequest req = ctx != null ? ctx.Request : null;
  1257. CacheDependency dep;
  1258. if (req != null) {
  1259. IDictionary <string, bool> deps = bp.ExtractDependencies ();
  1260. var files = new List <string> ();
  1261. string physicalPath;
  1262. physicalPath = req.MapPath (virtualPath);
  1263. if (File.Exists (physicalPath))
  1264. files.Add (physicalPath);
  1265. if (deps != null && deps.Count > 0) {
  1266. foreach (var d in deps) {
  1267. physicalPath = req.MapPath (d.Key);
  1268. if (!File.Exists (physicalPath))
  1269. continue;
  1270. if (!files.Contains (physicalPath))
  1271. files.Add (physicalPath);
  1272. }
  1273. }
  1274. dep = new CacheDependency (files.ToArray ());
  1275. } else
  1276. dep = null;
  1277. HttpRuntime.InternalCache.Add (BUILD_MANAGER_VIRTUAL_PATH_CACHE_PREFIX + virtualPath,
  1278. true,
  1279. dep,
  1280. Cache.NoAbsoluteExpiration,
  1281. Cache.NoSlidingExpiration,
  1282. CacheItemPriority.High,
  1283. new CacheItemRemovedCallback (OnVirtualPathChanged));
  1284. }
  1285. }
  1286. }