AssemblyBuilder.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. //
  2. // System.Web.Compilation.AssemblyBuilder
  3. //
  4. // Authors:
  5. // Chris Toshok ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. //
  8. // (C) 2006 Novell, Inc (http://www.novell.com)
  9. //
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining
  12. // a copy of this software and associated documentation files (the
  13. // "Software"), to deal in the Software without restriction, including
  14. // without limitation the rights to use, copy, modify, merge, publish,
  15. // distribute, sublicense, and/or sell copies of the Software, and to
  16. // permit persons to whom the Software is furnished to do so, subject to
  17. // the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be
  20. // included in all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. //
  30. #if NET_2_0
  31. using System;
  32. using System.CodeDom;
  33. using System.CodeDom.Compiler;
  34. using System.Collections.Generic;
  35. using System.Collections.Specialized;
  36. using System.IO;
  37. using System.Reflection;
  38. using System.Web.Configuration;
  39. using System.Web.Util;
  40. namespace System.Web.Compilation {
  41. public class AssemblyBuilder {
  42. static bool KeepFiles = (Environment.GetEnvironmentVariable ("MONO_ASPNET_NODELETE") != null);
  43. CodeDomProvider provider;
  44. List <CodeCompileUnit> units;
  45. List <string> source_files;
  46. List <string> referenced_assemblies;
  47. Dictionary <string, string> resource_files;
  48. TempFileCollection temp_files;
  49. //TODO: there should be a Compile () method here which is where all the compilation exceptions are thrown from.
  50. internal AssemblyBuilder (CodeDomProvider provider)
  51. : this (null, provider)
  52. {}
  53. internal AssemblyBuilder (string virtualPath, CodeDomProvider provider)
  54. {
  55. this.provider = provider;
  56. units = new List <CodeCompileUnit> ();
  57. temp_files = new TempFileCollection ();
  58. referenced_assemblies = new List <string> ();
  59. CompilationSection section;
  60. if (virtualPath != null)
  61. section = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation", virtualPath);
  62. else
  63. section = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation");
  64. string tempdir = section.TempDirectory;
  65. if (tempdir == null || tempdir == "")
  66. tempdir = AppDomain.CurrentDomain.SetupInformation.DynamicBase;
  67. temp_files = new TempFileCollection (tempdir, KeepFiles);
  68. }
  69. internal TempFileCollection TempFiles {
  70. get { return temp_files; }
  71. }
  72. internal CodeCompileUnit [] GetUnitsAsArray ()
  73. {
  74. CodeCompileUnit [] result = new CodeCompileUnit [units.Count];
  75. units.CopyTo (result, 0);
  76. return result;
  77. }
  78. List <string> SourceFiles {
  79. get {
  80. if (source_files == null)
  81. source_files = new List <string> ();
  82. return source_files;
  83. }
  84. }
  85. Dictionary <string, string> ResourceFiles {
  86. get {
  87. if (resource_files == null)
  88. resource_files = new Dictionary <string, string> ();
  89. return resource_files;
  90. }
  91. }
  92. public void AddAssemblyReference (Assembly a)
  93. {
  94. if (a == null)
  95. throw new ArgumentNullException ("a");
  96. referenced_assemblies.Add (a.Location);
  97. }
  98. internal void AddCodeCompileUnit (CodeCompileUnit compileUnit)
  99. {
  100. if (compileUnit == null)
  101. throw new ArgumentNullException ("compileUnit");
  102. units.Add (compileUnit);
  103. }
  104. public void AddCodeCompileUnit (BuildProvider buildProvider, CodeCompileUnit compileUnit)
  105. {
  106. if (buildProvider == null)
  107. throw new ArgumentNullException ("buildProvider");
  108. if (compileUnit == null)
  109. throw new ArgumentNullException ("compileUnit");
  110. units.Add (compileUnit);
  111. }
  112. public TextWriter CreateCodeFile (BuildProvider buildProvider)
  113. {
  114. if (buildProvider == null)
  115. throw new ArgumentNullException ("buildProvider");
  116. // Generate a file name with the correct source language extension
  117. string filename = GetTempFilePhysicalPath (provider.FileExtension);
  118. SourceFiles.Add (filename);
  119. return new StreamWriter (File.OpenWrite (filename), WebEncoding.FileEncoding);
  120. }
  121. internal void AddCodeFile (string path)
  122. {
  123. if (path == null || path.Length == 0)
  124. return;
  125. string extension = Path.GetExtension (path);
  126. if (extension == null || extension.Length == 0)
  127. return; // maybe better to throw an exception here?
  128. extension = extension.Substring (1);
  129. string filename = GetTempFilePhysicalPath (extension);
  130. File.Copy (path, filename, true);
  131. SourceFiles.Add (filename);
  132. }
  133. public Stream CreateEmbeddedResource (BuildProvider buildProvider, string name)
  134. {
  135. if (buildProvider == null)
  136. throw new ArgumentNullException ("buildProvider");
  137. if (name == null || name == "")
  138. throw new ArgumentNullException ("name");
  139. string filename = GetTempFilePhysicalPath ("resource");
  140. Stream stream = File.OpenWrite (filename);
  141. ResourceFiles [name] = filename;
  142. return stream;
  143. }
  144. [MonoTODO ("Not implemented, does nothing")]
  145. public void GenerateTypeFactory (string typeName)
  146. {
  147. // Do nothing by now.
  148. }
  149. public string GetTempFilePhysicalPath (string extension)
  150. {
  151. if (extension == null)
  152. throw new ArgumentNullException ("extension");
  153. return temp_files.AddExtension (String.Concat ("_", temp_files.Count, ".", extension), true);
  154. }
  155. public CodeDomProvider CodeDomProvider {
  156. get { return provider; }
  157. }
  158. internal CompilerResults BuildAssembly (CompilerParameters options)
  159. {
  160. return BuildAssembly (null, options);
  161. }
  162. internal CompilerResults BuildAssembly (string virtualPath, CompilerParameters options)
  163. {
  164. if (options == null)
  165. throw new ArgumentNullException ("options");
  166. CompilerResults results;
  167. CodeCompileUnit [] units = GetUnitsAsArray ();
  168. // Since we may have some source files and some code
  169. // units, we generate code from all of them and then
  170. // compile the assembly from the set of temporary source
  171. // files. This also facilates possible debugging for the
  172. // end user, since they get the code beforehand.
  173. List <string> files = SourceFiles;
  174. string filename;
  175. StreamWriter sw = null;
  176. foreach (CodeCompileUnit unit in units) {
  177. filename = GetTempFilePhysicalPath (provider.FileExtension);
  178. try {
  179. sw = new StreamWriter (File.OpenWrite (filename), WebEncoding.FileEncoding);
  180. provider.GenerateCodeFromCompileUnit (unit, sw, null);
  181. files.Add (filename);
  182. } catch {
  183. throw;
  184. } finally {
  185. if (sw != null) {
  186. sw.Flush ();
  187. sw.Close ();
  188. }
  189. }
  190. }
  191. Dictionary <string, string> resources = ResourceFiles;
  192. foreach (KeyValuePair <string, string> de in resources)
  193. options.EmbeddedResources.Add (de.Value);
  194. foreach (string refasm in referenced_assemblies)
  195. options.ReferencedAssemblies.Add (refasm);
  196. results = provider.CompileAssemblyFromFile (options, files.ToArray ());
  197. if (results.NativeCompilerReturnValue != 0) {
  198. string fileText = null;
  199. try {
  200. using (StreamReader sr = File.OpenText (results.Errors [0].FileName)) {
  201. fileText = sr.ReadToEnd ();
  202. }
  203. } catch (Exception) {}
  204. throw new CompilationException (virtualPath, results.Errors, fileText);
  205. }
  206. Assembly assembly = results.CompiledAssembly;
  207. if (assembly == null) {
  208. if (!File.Exists (options.OutputAssembly)) {
  209. results.TempFiles.Delete ();
  210. throw new CompilationException (virtualPath, results.Errors,
  211. "No assembly returned after compilation!?");
  212. }
  213. try {
  214. results.CompiledAssembly = Assembly.LoadFrom (options.OutputAssembly);
  215. } catch (Exception ex) {
  216. results.TempFiles.Delete ();
  217. throw new HttpException ("Unable to load compiled assembly", ex);
  218. }
  219. }
  220. if (!KeepFiles)
  221. results.TempFiles.Delete ();
  222. return results;
  223. }
  224. }
  225. }
  226. #endif