TemplateFactory.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. //
  2. // System.Web.Compilation.TemplateFactory
  3. //
  4. // Authors:
  5. // Gonzalo Paniagua Javier ([email protected])
  6. //
  7. // (C) 2002 Ximian, Inc (http://www.ximian.com)
  8. //
  9. using System;
  10. using System.Collections;
  11. using System.Diagnostics;
  12. using System.IO;
  13. using System.Reflection;
  14. using System.Text;
  15. using System.Web.UI;
  16. using System.Web.Util;
  17. //TODO: should use private bin to store dlls (when AppDomain and Assembly.Load know about it?)
  18. namespace System.Web.Compilation
  19. {
  20. class CompiledTypeData
  21. {
  22. string csFile;
  23. string aspxFile;
  24. Type type;
  25. DateTime since;
  26. //TODO: ArrayList fileDependencies;
  27. public CompiledTypeData (string aspxFile, string csFile, Type type, DateTime since)
  28. {
  29. this.aspxFile = aspxFile;
  30. this.csFile = csFile;
  31. this.type = type;
  32. this.since = since;
  33. }
  34. public bool IsNewer (DateTime dt)
  35. {
  36. return (dt > since);
  37. }
  38. public Type Type
  39. {
  40. get { return type; }
  41. set { type = value; }
  42. }
  43. public DateTime Since
  44. {
  45. get { return since; }
  46. set { since = value; }
  47. }
  48. }
  49. class TemplateFactory
  50. {
  51. internal class PageBuilder
  52. {
  53. private StringBuilder cscOptions;
  54. private string csFileName;
  55. private string className;
  56. public static char dirSeparator = Path.DirectorySeparatorChar;
  57. private static Hashtable cachedData = new Hashtable ();
  58. private static Random rnd_file = new Random ();
  59. private PageBuilder ()
  60. {
  61. }
  62. internal PageBuilder (string fileName)
  63. {
  64. csFileName = fileName;
  65. cscOptions = new StringBuilder ();
  66. cscOptions.Append ("/target:library ");
  67. AddReference ("System.Data");
  68. AddReference ("System.Web");
  69. AddReference ("System.Drawing");
  70. }
  71. internal Type Build ()
  72. {
  73. string dll;
  74. StreamReader st_file = new StreamReader (File.OpenRead (csFileName));
  75. StringReader file_content = new StringReader (st_file.ReadToEnd ());
  76. st_file.Close ();
  77. if (GetBuildOptions (file_content) == false)
  78. return null;
  79. dll = rnd_file.Next () + Path.GetFileName (csFileName).Replace (".cs", ".dll");
  80. if (Compile (csFileName, dll) == true){
  81. Assembly assembly = Assembly.LoadFrom (dll);
  82. Type type = assembly.GetType ("ASP." + className);
  83. return type;
  84. }
  85. return null;
  86. }
  87. private static bool RunProcess (string exe, string arguments, string output_file, string script_file)
  88. {
  89. Console.WriteLine ("{0} {1}", exe, arguments);
  90. Console.WriteLine ("Output goes to {0}", output_file);
  91. Console.WriteLine ("Script file is {0}", script_file);
  92. Process proc = new Process ();
  93. proc.StartInfo.FileName = exe;
  94. proc.StartInfo.Arguments = arguments;
  95. proc.StartInfo.UseShellExecute = false;
  96. proc.StartInfo.RedirectStandardOutput = true;
  97. proc.Start ();
  98. string poutput = proc.StandardOutput.ReadToEnd();
  99. proc.WaitForExit ();
  100. int result = proc.ExitCode;
  101. proc.Close ();
  102. StreamWriter cmd_output = new StreamWriter (File.Create (output_file));
  103. cmd_output.Write (poutput);
  104. cmd_output.Close ();
  105. StreamWriter bat_output = new StreamWriter (File.Create (script_file));
  106. bat_output.Write (exe + " " + arguments);
  107. bat_output.Close ();
  108. return (result == 0);
  109. }
  110. private bool GetBuildOptions (StringReader genCode)
  111. {
  112. string line;
  113. string dll;
  114. while ((line = genCode.ReadLine ()) != String.Empty) {
  115. if (line.StartsWith ("//<class ")){
  116. className = GetAttributeValue (line, "name");
  117. } else if (line.StartsWith ("//<compileandreference ")) {
  118. string src = GetAttributeValue (line, "src");
  119. dll = src.Replace (".cs", ".dll"); //FIXME
  120. //File.Delete (dll);
  121. if (Compile (src, dll) == false){
  122. Console.WriteLine ("Error compiling {0}. See the output file.", src);
  123. return false;
  124. }
  125. AddReference (dll.Replace (".dll", ""));
  126. } else if (line.StartsWith ("//<reference ")) {
  127. dll = GetAttributeValue (line, "dll");
  128. AddReference (dll);
  129. } else if (line.StartsWith ("//<compileroptions ")) {
  130. string options = GetAttributeValue (line, "options");
  131. cscOptions.Append (" " + options + " ");
  132. } else {
  133. Console.WriteLine ("This is the build option line i get:\n" + line);
  134. return false;
  135. }
  136. }
  137. return true;
  138. }
  139. private void AddReference (string reference)
  140. {
  141. string arg = String.Format ("/r:{0}.dll ", reference);
  142. cscOptions.Append (arg);
  143. }
  144. private string GetAttributeValue (string line, string att)
  145. {
  146. string att_start = att + "=\"";
  147. int begin = line.IndexOf (att_start);
  148. int end = line.Substring (begin + att_start.Length).IndexOf ('"');
  149. if (begin == -1 || end == -1)
  150. throw new ApplicationException ("Error in reference option:\n" + line);
  151. return line.Substring (begin + att_start.Length, end);
  152. }
  153. private bool Compile (string csName, string dllName)
  154. {
  155. cscOptions.AppendFormat ("/out:{0} ", dllName);
  156. cscOptions.Append (csName);
  157. string cmdline = cscOptions.ToString ();
  158. string noext = csName.Replace (".cs", "");
  159. string output_file = noext + "_compilation_output.txt";
  160. string bat_file = noext + "_compile_command.bat";
  161. return RunProcess ("mcs", cmdline, output_file, bat_file);
  162. }
  163. }
  164. static object compiling = new object ();
  165. static Hashtable compiledTypes = new Hashtable ();
  166. internal static string CompilationOutputFileName (string fileName)
  167. {
  168. string name = "xsp_" + Path.GetFileName (fileName).Replace (".aspx", ".txt");
  169. return "output" + PageBuilder.dirSeparator + "output_from_compilation_" + name;
  170. }
  171. internal static string GeneratedXspFileName (string fileName)
  172. {
  173. string name = Path.GetFileName (fileName).Replace (".aspx", ".cs");
  174. return "output" + PageBuilder.dirSeparator + "xsp_" + name;
  175. }
  176. private TemplateFactory ()
  177. {
  178. }
  179. static Type AlreadyGotIt (string aspxFile, ref DateTime filedt)
  180. {
  181. WebTrace.PushContext ("TemplateFactory.AlreadyGotIt");
  182. WebTrace.WriteLine ("Start: {0}", aspxFile);
  183. if (!compiledTypes.Contains (aspxFile)) {
  184. WebTrace.WriteLine ("File {0} not already compiled", filedt);
  185. WebTrace.PopContext ();
  186. return null;
  187. }
  188. CompiledTypeData data = (CompiledTypeData) compiledTypes [aspxFile];
  189. try {
  190. filedt = File.GetLastWriteTime (aspxFile);
  191. } catch {
  192. WebTrace.WriteLine ("Error getting date for {0}", aspxFile);
  193. WebTrace.PopContext ();
  194. return null;
  195. }
  196. if (data.IsNewer (filedt)) {
  197. compiledTypes.Remove (aspxFile);
  198. WebTrace.WriteLine ("aspx modified: {0}", filedt);
  199. WebTrace.PopContext ();
  200. return null;
  201. }
  202. WebTrace.WriteLine ("End: {0}", data.Type);
  203. WebTrace.PopContext ();
  204. return data.Type;
  205. }
  206. internal static Type GetTypeFromSource (string aspxFile, string csFile)
  207. {
  208. DateTime filedt = DateTime.Now;
  209. Type type = AlreadyGotIt (aspxFile, ref filedt) as Type;
  210. if (type != null)
  211. return type;
  212. if (csFile == null || !File.Exists (csFile))
  213. return null; //FIXME: throw an exception if the file does not exists
  214. PageBuilder builder = new PageBuilder (csFile);
  215. lock (compiling) {
  216. type = AlreadyGotIt (aspxFile, ref filedt) as Type;
  217. if (type != null)
  218. return type;
  219. type = builder.Build ();
  220. }
  221. if (type == null)
  222. return null;
  223. CompiledTypeData data = new CompiledTypeData (aspxFile, csFile, type, filedt);
  224. compiledTypes.Add (aspxFile, data);
  225. return type;
  226. }
  227. }
  228. }