TemplateParser.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155
  1. //
  2. // System.Web.UI.TemplateParser
  3. //
  4. // Authors:
  5. // Duncan Mak ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. //
  8. // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
  9. // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
  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. using System.CodeDom.Compiler;
  31. using System.Collections;
  32. using System.ComponentModel;
  33. using System.Globalization;
  34. using System.IO;
  35. using System.Reflection;
  36. using System.Security.Permissions;
  37. using System.Web.Compilation;
  38. using System.Web.Configuration;
  39. using System.Web.Hosting;
  40. using System.Web.Util;
  41. #if NET_2_0
  42. using System.Collections.Generic;
  43. #endif
  44. namespace System.Web.UI {
  45. internal class ServerSideScript
  46. {
  47. public readonly string Script;
  48. public readonly ILocation Location;
  49. public ServerSideScript (string script, ILocation location)
  50. {
  51. Script = script;
  52. Location = location;
  53. }
  54. }
  55. // CAS
  56. [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  57. [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  58. public abstract class TemplateParser : BaseParser
  59. {
  60. string inputFile;
  61. string text;
  62. string privateBinPath;
  63. Hashtable mainAttributes;
  64. ArrayList dependencies;
  65. ArrayList assemblies;
  66. Hashtable anames;
  67. ArrayList imports;
  68. ArrayList interfaces;
  69. ArrayList scripts;
  70. Type baseType;
  71. bool baseTypeIsGlobal = true;
  72. string className;
  73. RootBuilder rootBuilder;
  74. bool debug;
  75. string compilerOptions;
  76. string language;
  77. bool implicitLanguage;
  78. bool strictOn = false;
  79. bool explicitOn = false;
  80. bool linePragmasOn = false;
  81. bool output_cache;
  82. int oc_duration;
  83. string oc_header, oc_custom, oc_param, oc_controls;
  84. #if NET_2_0
  85. string oc_content_encodings;
  86. #endif
  87. bool oc_shared;
  88. OutputCacheLocation oc_location;
  89. CultureInfo invariantCulture = CultureInfo.InvariantCulture;
  90. #if NET_2_0
  91. string src;
  92. bool srcIsLegacy;
  93. string partialClassName;
  94. string codeFileBaseClass;
  95. string metaResourceKey;
  96. Type codeFileBaseClassType;
  97. List <UnknownAttributeDescriptor> unknownMainAttributes;
  98. Stack <string> includeDirs;
  99. #else
  100. Stack includeDirs;
  101. #endif
  102. ILocation directiveLocation;
  103. byte[] md5checksum;
  104. Assembly srcAssembly;
  105. int appAssemblyIndex = -1;
  106. internal TemplateParser ()
  107. {
  108. LoadConfigDefaults ();
  109. imports = new ArrayList ();
  110. #if NET_2_0
  111. AddNamespaces (imports);
  112. #else
  113. imports.Add ("System");
  114. imports.Add ("System.Collections");
  115. imports.Add ("System.Collections.Specialized");
  116. imports.Add ("System.Configuration");
  117. imports.Add ("System.Text");
  118. imports.Add ("System.Text.RegularExpressions");
  119. imports.Add ("System.Web");
  120. imports.Add ("System.Web.Caching");
  121. imports.Add ("System.Web.Security");
  122. imports.Add ("System.Web.SessionState");
  123. imports.Add ("System.Web.UI");
  124. imports.Add ("System.Web.UI.WebControls");
  125. imports.Add ("System.Web.UI.HtmlControls");
  126. #endif
  127. assemblies = new ArrayList ();
  128. #if NET_2_0
  129. CompilationSection compConfig = CompilationConfig;
  130. bool addAssembliesInBin = false;
  131. foreach (AssemblyInfo info in compConfig.Assemblies) {
  132. if (info.Assembly == "*")
  133. addAssembliesInBin = true;
  134. else
  135. AddAssemblyByName (info.Assembly);
  136. }
  137. if (addAssembliesInBin)
  138. AddAssembliesInBin ();
  139. foreach (NamespaceInfo info in PagesConfig.Namespaces) {
  140. imports.Add (info.Namespace);
  141. }
  142. #else
  143. CompilationConfiguration compConfig = CompilationConfig;
  144. foreach (string a in compConfig.Assemblies)
  145. AddAssemblyByName (a);
  146. if (compConfig.AssembliesInBin)
  147. AddAssembliesInBin ();
  148. #endif
  149. language = compConfig.DefaultLanguage;
  150. implicitLanguage = true;
  151. }
  152. internal virtual void LoadConfigDefaults ()
  153. {
  154. debug = CompilationConfig.Debug;
  155. }
  156. internal void AddApplicationAssembly ()
  157. {
  158. if (Context.ApplicationInstance == null)
  159. return; // this may happen if we have Global.asax and have
  160. // controls registered from Web.Config
  161. string location = Context.ApplicationInstance.AssemblyLocation;
  162. if (location != typeof (TemplateParser).Assembly.Location) {
  163. appAssemblyIndex = assemblies.Add (location);
  164. }
  165. }
  166. protected abstract Type CompileIntoType ();
  167. #if NET_2_0
  168. void AddNamespaces (ArrayList imports)
  169. {
  170. if (BuildManager.HaveResources)
  171. imports.Add ("System.Resources");
  172. PagesSection pages = WebConfigurationManager.GetSection ("system.web/pages") as PagesSection;
  173. if (pages == null)
  174. return;
  175. NamespaceCollection namespaces = pages.Namespaces;
  176. if (namespaces == null || namespaces.Count == 0)
  177. return;
  178. foreach (NamespaceInfo nsi in namespaces)
  179. imports.Add (nsi.Namespace);
  180. }
  181. #endif
  182. internal void RegisterCustomControl (string tagPrefix, string tagName, string src)
  183. {
  184. string realpath = null;
  185. bool fileExists = false;
  186. #if NET_2_0
  187. VirtualFile vf = null;
  188. VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
  189. VirtualPath vp = new VirtualPath (src, BaseVirtualDir);
  190. string vpAbsolute = vp.Absolute;
  191. if (vpp.FileExists (vpAbsolute)) {
  192. fileExists = true;
  193. vf = vpp.GetFile (vpAbsolute);
  194. if (vf != null)
  195. realpath = MapPath (vf.VirtualPath);
  196. }
  197. #else
  198. realpath = MapPath (src);
  199. fileExists = File.Exists (realpath);
  200. #endif
  201. if (!fileExists)
  202. throw new ParseException (Location, "Could not find file \"" + src + "\".");
  203. if (String.Compare (realpath, inputFile, false, invariantCulture) == 0)
  204. return;
  205. #if NET_2_0
  206. string vpath = vf.VirtualPath;
  207. #else
  208. string vpath = VirtualPathUtility.Combine (BaseVirtualDir, src);
  209. if (VirtualPathUtility.IsAbsolute (vpath))
  210. vpath = VirtualPathUtility.ToAppRelative (vpath);
  211. #endif
  212. Type type = null;
  213. AddDependency (vpath);
  214. try {
  215. #if NET_2_0
  216. type = BuildManager.GetCompiledType (vpath);
  217. if (type == null)
  218. throw new ParseException (Location, "Error compiling user control '" + vpath + "'.");
  219. if (!(typeof (UserControl).IsAssignableFrom (type)))
  220. throw new ParseException (Location, "Type '" + type.ToString () + "' does not derive from 'System.Web.UI.UserControl'.");
  221. #else
  222. ArrayList other_deps = new ArrayList ();
  223. type = UserControlParser.GetCompiledType (vpath, realpath, other_deps, Context);
  224. foreach (string s in other_deps)
  225. AddDependency (s);
  226. #endif
  227. } catch (ParseException pe) {
  228. if (this is UserControlParser)
  229. throw new ParseException (Location, pe.Message, pe);
  230. throw;
  231. }
  232. AddAssembly (type.Assembly, true);
  233. RootBuilder.Foundry.RegisterFoundry (tagPrefix, tagName, type);
  234. }
  235. internal void RegisterNamespace (string tagPrefix, string ns, string assembly)
  236. {
  237. AddImport (ns);
  238. Assembly ass = null;
  239. if (assembly != null && assembly.Length > 0)
  240. ass = AddAssemblyByName (assembly);
  241. RootBuilder.Foundry.RegisterFoundry (tagPrefix, ass, ns);
  242. }
  243. internal virtual void HandleOptions (object obj)
  244. {
  245. }
  246. internal static string GetOneKey (Hashtable tbl)
  247. {
  248. foreach (object key in tbl.Keys)
  249. return key.ToString ();
  250. return null;
  251. }
  252. internal virtual void AddDirective (string directive, Hashtable atts)
  253. {
  254. if (String.Compare (directive, DefaultDirectiveName, true) == 0) {
  255. if (mainAttributes != null)
  256. ThrowParseException ("Only 1 " + DefaultDirectiveName + " is allowed");
  257. mainAttributes = atts;
  258. ProcessMainAttributes (mainAttributes);
  259. return;
  260. }
  261. int cmp = String.Compare ("Assembly", directive, true);
  262. if (cmp == 0) {
  263. string name = GetString (atts, "Name", null);
  264. string src = GetString (atts, "Src", null);
  265. if (atts.Count > 0)
  266. ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
  267. if (name == null && src == null)
  268. ThrowParseException ("You gotta specify Src or Name");
  269. if (name != null && src != null)
  270. ThrowParseException ("Src and Name cannot be used together");
  271. if (name != null) {
  272. AddAssemblyByName (name);
  273. } else {
  274. GetAssemblyFromSource (src);
  275. }
  276. return;
  277. }
  278. cmp = String.Compare ("Import", directive, true);
  279. if (cmp == 0) {
  280. string namesp = GetString (atts, "Namespace", null);
  281. if (atts.Count > 0)
  282. ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
  283. if (namesp != null && namesp != "")
  284. AddImport (namesp);
  285. return;
  286. }
  287. cmp = String.Compare ("Implements", directive, true);
  288. if (cmp == 0) {
  289. string ifacename = GetString (atts, "Interface", "");
  290. if (atts.Count > 0)
  291. ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
  292. Type iface = LoadType (ifacename);
  293. if (iface == null)
  294. ThrowParseException ("Cannot find type " + ifacename);
  295. if (!iface.IsInterface)
  296. ThrowParseException (iface + " is not an interface");
  297. AddInterface (iface.FullName);
  298. return;
  299. }
  300. cmp = String.Compare ("OutputCache", directive, true);
  301. if (cmp == 0) {
  302. HttpResponse response = HttpContext.Current.Response;
  303. if (response != null)
  304. response.Cache.SetValidUntilExpires (true);
  305. output_cache = true;
  306. if (atts ["Duration"] == null)
  307. ThrowParseException ("The directive is missing a 'duration' attribute.");
  308. if (atts ["VaryByParam"] == null && atts ["VaryByControl"] == null)
  309. ThrowParseException ("This directive is missing 'VaryByParam' " +
  310. "or 'VaryByControl' attribute, which should be set to \"none\", \"*\", " +
  311. "or a list of name/value pairs.");
  312. foreach (DictionaryEntry entry in atts) {
  313. string key = (string) entry.Key;
  314. switch (key.ToLower ()) {
  315. case "duration":
  316. oc_duration = Int32.Parse ((string) entry.Value);
  317. if (oc_duration < 1)
  318. ThrowParseException ("The 'duration' attribute must be set " +
  319. "to a positive integer value");
  320. break;
  321. #if NET_2_0
  322. case "varybycontentencodings":
  323. oc_content_encodings = (string) entry.Value;
  324. break;
  325. #endif
  326. case "varybyparam":
  327. oc_param = (string) entry.Value;
  328. if (String.Compare (oc_param, "none") == 0)
  329. oc_param = null;
  330. break;
  331. case "varybyheader":
  332. oc_header = (string) entry.Value;
  333. break;
  334. case "varybycustom":
  335. oc_custom = (string) entry.Value;
  336. break;
  337. case "location":
  338. if (!(this is PageParser))
  339. goto default;
  340. try {
  341. oc_location = (OutputCacheLocation) Enum.Parse (
  342. typeof (OutputCacheLocation), (string) entry.Value, true);
  343. } catch {
  344. ThrowParseException ("The 'location' attribute is case sensitive and " +
  345. "must be one of the following values: Any, Client, " +
  346. "Downstream, Server, None, ServerAndClient.");
  347. }
  348. break;
  349. case "varybycontrol":
  350. #if ONLY_1_1
  351. if (this is PageParser)
  352. goto default;
  353. #endif
  354. oc_controls = (string) entry.Value;
  355. break;
  356. case "shared":
  357. if (this is PageParser)
  358. goto default;
  359. try {
  360. oc_shared = Boolean.Parse ((string) entry.Value);
  361. } catch {
  362. ThrowParseException ("The 'shared' attribute is case sensitive" +
  363. " and must be set to 'true' or 'false'.");
  364. }
  365. break;
  366. default:
  367. ThrowParseException ("The '" + key + "' attribute is not " +
  368. "supported by the 'Outputcache' directive.");
  369. break;
  370. }
  371. }
  372. return;
  373. }
  374. ThrowParseException ("Unknown directive: " + directive);
  375. }
  376. internal Type LoadType (string typeName)
  377. {
  378. Type type = HttpApplication.LoadType (typeName);
  379. if (type == null)
  380. return null;
  381. Assembly asm = type.Assembly;
  382. string location = asm.Location;
  383. string dirname = Path.GetDirectoryName (location);
  384. bool doAddAssembly = true;
  385. if (dirname == HttpApplication.BinDirectory)
  386. doAddAssembly = false;
  387. if (doAddAssembly)
  388. AddAssembly (asm, true);
  389. return type;
  390. }
  391. void AddAssembliesInBin ()
  392. {
  393. foreach (string s in HttpApplication.BinDirectoryAssemblies)
  394. assemblies.Add (s);
  395. }
  396. internal virtual void AddInterface (string iface)
  397. {
  398. if (interfaces == null)
  399. interfaces = new ArrayList ();
  400. if (!interfaces.Contains (iface))
  401. interfaces.Add (iface);
  402. }
  403. internal virtual void AddImport (string namesp)
  404. {
  405. if (imports == null)
  406. imports = new ArrayList ();
  407. if (!imports.Contains (namesp))
  408. imports.Add (namesp);
  409. }
  410. internal virtual void AddSourceDependency (string filename)
  411. {
  412. if (dependencies != null && dependencies.Contains (filename))
  413. ThrowParseException ("Circular file references are not allowed. File: " + filename);
  414. AddDependency (filename);
  415. }
  416. internal virtual void AddDependency (string filename)
  417. {
  418. if (filename == "")
  419. return;
  420. if (dependencies == null)
  421. dependencies = new ArrayList ();
  422. if (!dependencies.Contains (filename))
  423. dependencies.Add (filename);
  424. }
  425. internal virtual void AddAssembly (Assembly assembly, bool fullPath)
  426. {
  427. if (assembly.Location == "")
  428. return;
  429. if (anames == null)
  430. anames = new Hashtable ();
  431. string name = assembly.GetName ().Name;
  432. string loc = assembly.Location;
  433. if (fullPath) {
  434. if (!assemblies.Contains (loc)) {
  435. assemblies.Add (loc);
  436. }
  437. anames [name] = loc;
  438. anames [loc] = assembly;
  439. } else {
  440. if (!assemblies.Contains (name)) {
  441. assemblies.Add (name);
  442. }
  443. anames [name] = assembly;
  444. }
  445. }
  446. internal virtual Assembly AddAssemblyByFileName (string filename)
  447. {
  448. Assembly assembly = null;
  449. Exception error = null;
  450. try {
  451. assembly = Assembly.LoadFrom (filename);
  452. } catch (Exception e) { error = e; }
  453. if (assembly == null)
  454. ThrowParseException ("Assembly " + filename + " not found", error);
  455. AddAssembly (assembly, true);
  456. return assembly;
  457. }
  458. internal virtual Assembly AddAssemblyByName (string name)
  459. {
  460. if (anames == null)
  461. anames = new Hashtable ();
  462. if (anames.Contains (name)) {
  463. object o = anames [name];
  464. if (o is string)
  465. o = anames [o];
  466. return (Assembly) o;
  467. }
  468. Assembly assembly = null;
  469. Exception error = null;
  470. try {
  471. assembly = Assembly.Load (name);
  472. } catch (Exception e) { error = e; }
  473. if (assembly == null) {
  474. try {
  475. assembly = Assembly.LoadWithPartialName (name);
  476. } catch (Exception e) { error = e; }
  477. }
  478. if (assembly == null)
  479. ThrowParseException ("Assembly " + name + " not found", error);
  480. AddAssembly (assembly, true);
  481. return assembly;
  482. }
  483. internal virtual void ProcessMainAttributes (Hashtable atts)
  484. {
  485. directiveLocation = new System.Web.Compilation.Location (Location);
  486. #if NET_2_0
  487. CompilationSection compConfig;
  488. #else
  489. CompilationConfiguration compConfig;
  490. #endif
  491. compConfig = CompilationConfig;
  492. atts.Remove ("Description"); // ignored
  493. #if NET_1_1
  494. atts.Remove ("CodeBehind"); // ignored
  495. #endif
  496. atts.Remove ("AspCompat"); // ignored
  497. debug = GetBool (atts, "Debug", compConfig.Debug);
  498. compilerOptions = GetString (atts, "CompilerOptions", "");
  499. language = GetString (atts, "Language", "");
  500. if (language.Length != 0)
  501. implicitLanguage = false;
  502. else
  503. language = compConfig.DefaultLanguage;
  504. strictOn = GetBool (atts, "Strict", compConfig.Strict);
  505. explicitOn = GetBool (atts, "Explicit", compConfig.Explicit);
  506. linePragmasOn = GetBool (atts, "LinePragmas", false);
  507. string inherits = GetString (atts, "Inherits", null);
  508. string srcRealPath = null;
  509. #if NET_2_0
  510. // In ASP 2, the source file is actually integrated with
  511. // the generated file via the use of partial classes. This
  512. // means that the code file has to be confirmed, but not
  513. // used at this point.
  514. src = GetString (atts, "CodeFile", null);
  515. codeFileBaseClass = GetString (atts, "CodeFileBaseClass", null);
  516. if (src == null && codeFileBaseClass != null)
  517. ThrowParseException ("The 'CodeFileBaseClass' attribute cannot be used without a 'CodeFile' attribute");
  518. string legacySrc = GetString (atts, "Src", null);
  519. if (legacySrc != null) {
  520. legacySrc = UrlUtils.Combine (BaseVirtualDir, legacySrc);
  521. GetAssemblyFromSource (legacySrc);
  522. if (src == null) {
  523. src = legacySrc;
  524. legacySrc = MapPath (legacySrc, false);
  525. srcRealPath = legacySrc;
  526. if (!File.Exists (srcRealPath))
  527. ThrowParseException ("File " + src + " not found");
  528. srcIsLegacy = true;
  529. } else
  530. legacySrc = MapPath (legacySrc, false);
  531. AddDependency (legacySrc);
  532. }
  533. if (!srcIsLegacy && src != null && inherits != null) {
  534. // Make sure the source exists
  535. src = UrlUtils.Combine (BaseVirtualDir, src);
  536. srcRealPath = MapPath (src, false);
  537. if (!HostingEnvironment.VirtualPathProvider.FileExists (src))
  538. ThrowParseException ("File " + src + " not found");
  539. // We are going to create a partial class that shares
  540. // the same name as the inherits tag, so reset the
  541. // name. The base type is changed because it is the
  542. // code file's responsibilty to extend the classes
  543. // needed.
  544. partialClassName = inherits;
  545. // Add the code file as an option to the
  546. // compiler. This lets both files be compiled at once.
  547. compilerOptions += " \"" + srcRealPath + "\"";
  548. if (codeFileBaseClass != null) {
  549. try {
  550. codeFileBaseClassType = LoadType (codeFileBaseClass);
  551. } catch (Exception) {
  552. }
  553. if (codeFileBaseClassType == null)
  554. ThrowParseException ("Could not load type '{0}'", codeFileBaseClass);
  555. }
  556. } else if (inherits != null) {
  557. // We just set the inherits directly because this is a
  558. // Single-Page model.
  559. SetBaseType (inherits);
  560. }
  561. #else
  562. string src = GetString (atts, "Src", null);
  563. if (src != null) {
  564. srcRealPath = MapPath (src, false);
  565. srcAssembly = GetAssemblyFromSource (src);
  566. }
  567. if (inherits != null)
  568. SetBaseType (inherits);
  569. #endif
  570. if (src != null) {
  571. if (VirtualPathUtility.IsAbsolute (src))
  572. src = VirtualPathUtility.ToAppRelative (src);
  573. AddDependency (src);
  574. }
  575. className = GetString (atts, "ClassName", null);
  576. if (className != null) {
  577. #if NET_2_0
  578. string [] identifiers = className.Split ('.');
  579. for (int i = 0; i < identifiers.Length; i++)
  580. if (!CodeGenerator.IsValidLanguageIndependentIdentifier (identifiers [i]))
  581. ThrowParseException (String.Format ("'{0}' is not a valid "
  582. + "value for attribute 'classname'.", className));
  583. #else
  584. if (!CodeGenerator.IsValidLanguageIndependentIdentifier (className))
  585. ThrowParseException (String.Format ("'{0}' is not a valid "
  586. + "value for attribute 'classname'.", className));
  587. #endif
  588. }
  589. #if NET_2_0
  590. if (this is TemplateControlParser)
  591. metaResourceKey = GetString (atts, "meta:resourcekey", null);
  592. if (inherits != null && (this is PageParser || this is UserControlParser) && atts.Count > 0) {
  593. if (unknownMainAttributes == null)
  594. unknownMainAttributes = new List <UnknownAttributeDescriptor> ();
  595. string key, val;
  596. foreach (DictionaryEntry de in atts) {
  597. key = de.Key as string;
  598. val = de.Value as string;
  599. if (String.IsNullOrEmpty (key) || String.IsNullOrEmpty (val))
  600. continue;
  601. CheckUnknownAttribute (key, val, inherits);
  602. }
  603. return;
  604. }
  605. #endif
  606. if (atts.Count > 0)
  607. ThrowParseException ("Unknown attribute: " + GetOneKey (atts));
  608. }
  609. #if NET_2_0
  610. void CheckUnknownAttribute (string name, string val, string inherits)
  611. {
  612. MemberInfo mi = null;
  613. bool missing = false;
  614. string memberName = name.Trim ().ToLower (CultureInfo.InvariantCulture);
  615. Type parent = codeFileBaseClassType;
  616. if (parent == null)
  617. parent = baseType;
  618. try {
  619. MemberInfo[] infos = parent.GetMember (memberName,
  620. MemberTypes.Field | MemberTypes.Property,
  621. BindingFlags.Public | BindingFlags.Instance |
  622. BindingFlags.IgnoreCase | BindingFlags.Static);
  623. if (infos.Length != 0) {
  624. // prefer public properties to public methods (it's what MS.NET does)
  625. foreach (MemberInfo tmp in infos) {
  626. if (tmp is PropertyInfo) {
  627. mi = tmp;
  628. break;
  629. }
  630. }
  631. if (mi == null)
  632. mi = infos [0];
  633. } else
  634. missing = true;
  635. } catch (Exception) {
  636. missing = true;
  637. }
  638. if (missing)
  639. ThrowParseException (
  640. "Error parsing attribute '{0}': Type '{1}' does not have a public property named '{0}'",
  641. memberName, inherits);
  642. Type memberType = null;
  643. if (mi is PropertyInfo) {
  644. PropertyInfo pi = mi as PropertyInfo;
  645. if (!pi.CanWrite)
  646. ThrowParseException (
  647. "Error parsing attribute '{0}': The '{0}' property is read-only and cannot be set.",
  648. memberName);
  649. memberType = pi.PropertyType;
  650. } else if (mi is FieldInfo) {
  651. memberType = ((FieldInfo)mi).FieldType;
  652. } else
  653. ThrowParseException ("Could not determine member the kind of '{0}' in base type '{1}",
  654. memberName, inherits);
  655. TypeConverter converter = TypeDescriptor.GetConverter (memberType);
  656. bool convertible = true;
  657. object value = null;
  658. if (converter == null || !converter.CanConvertFrom (typeof (string)))
  659. convertible = false;
  660. if (convertible) {
  661. try {
  662. value = converter.ConvertFromInvariantString (val);
  663. } catch (Exception) {
  664. convertible = false;
  665. }
  666. }
  667. if (!convertible)
  668. ThrowParseException ("Error parsing attribute '{0}': Cannot create an object of type '{1}' from its string representation '{2}' for the '{3}' property.",
  669. memberName, memberType, val, mi.Name);
  670. UnknownAttributeDescriptor desc = new UnknownAttributeDescriptor (mi, value);
  671. unknownMainAttributes.Add (desc);
  672. }
  673. #endif
  674. internal void SetBaseType (string type)
  675. {
  676. if (type == null || type == DefaultBaseTypeName) {
  677. baseType = DefaultBaseType;
  678. return;
  679. }
  680. Type parent = null;
  681. if (srcAssembly != null)
  682. parent = srcAssembly.GetType (type);
  683. if (parent == null)
  684. parent = LoadType (type);
  685. if (parent == null)
  686. ThrowParseException ("Cannot find type " + type);
  687. if (!DefaultBaseType.IsAssignableFrom (parent))
  688. ThrowParseException ("The parent type '" + type + "' does not derive from " + DefaultBaseType);
  689. baseType = parent;
  690. }
  691. internal void SetLanguage (string language)
  692. {
  693. this.language = language;
  694. implicitLanguage = false;
  695. }
  696. internal void PushIncludeDir (string dir)
  697. {
  698. if (includeDirs == null) {
  699. #if NET_2_0
  700. includeDirs = new Stack <string> (1);
  701. #else
  702. includeDirs = new Stack (1);
  703. #endif
  704. }
  705. includeDirs.Push (dir);
  706. }
  707. internal string PopIncludeDir ()
  708. {
  709. if (includeDirs == null || includeDirs.Count == 0)
  710. return null;
  711. return includeDirs.Pop () as string;
  712. }
  713. Assembly GetAssemblyFromSource (string vpath)
  714. {
  715. vpath = UrlUtils.Combine (BaseVirtualDir, vpath);
  716. string realPath = MapPath (vpath, false);
  717. if (!File.Exists (realPath))
  718. ThrowParseException ("File " + vpath + " not found");
  719. AddSourceDependency (vpath);
  720. CompilerResults result;
  721. #if NET_2_0
  722. string tmp;
  723. CompilerParameters parameters;
  724. CodeDomProvider provider = BaseCompiler.CreateProvider (HttpContext.Current, language, out parameters, out tmp);
  725. if (provider == null)
  726. throw new HttpException ("Cannot find provider for language '" + language + "'.");
  727. AssemblyBuilder abuilder = new AssemblyBuilder (provider);
  728. abuilder.CompilerOptions = parameters;
  729. abuilder.AddAssemblyReference (BuildManager.GetReferencedAssemblies () as List <Assembly>);
  730. abuilder.AddCodeFile (realPath);
  731. result = abuilder.BuildAssembly (new VirtualPath (vpath));
  732. #else
  733. result = CachingCompiler.Compile (language, realPath, realPath, assemblies, Debug);
  734. #endif
  735. if (result.NativeCompilerReturnValue != 0) {
  736. using (StreamReader reader = new StreamReader (realPath)) {
  737. throw new CompilationException (realPath, result.Errors, reader.ReadToEnd ());
  738. }
  739. }
  740. AddAssembly (result.CompiledAssembly, true);
  741. return result.CompiledAssembly;
  742. }
  743. internal abstract string DefaultBaseTypeName { get; }
  744. internal abstract string DefaultDirectiveName { get; }
  745. internal byte[] MD5Checksum {
  746. get { return md5checksum; }
  747. set { md5checksum = value; }
  748. }
  749. internal Type DefaultBaseType {
  750. get {
  751. Type type = Type.GetType (DefaultBaseTypeName, true);
  752. return type;
  753. }
  754. }
  755. internal ILocation DirectiveLocation {
  756. get { return directiveLocation; }
  757. }
  758. #if NET_2_0
  759. internal VirtualPath VirtualPath {
  760. get;
  761. set;
  762. }
  763. #endif
  764. internal string ParserDir {
  765. get {
  766. if (includeDirs == null || includeDirs.Count == 0)
  767. return BaseDir;
  768. return includeDirs.Peek () as string;
  769. }
  770. }
  771. internal string InputFile
  772. {
  773. get { return inputFile; }
  774. set { inputFile = value; }
  775. }
  776. #if NET_2_0
  777. internal bool IsPartial {
  778. get { return (!srcIsLegacy && src != null); }
  779. }
  780. internal string CodeBehindSource {
  781. get {
  782. if (srcIsLegacy)
  783. return null;
  784. return src;
  785. }
  786. }
  787. internal string PartialClassName {
  788. get { return partialClassName; }
  789. }
  790. internal string CodeFileBaseClass {
  791. get { return codeFileBaseClass; }
  792. }
  793. internal string MetaResourceKey {
  794. get { return metaResourceKey; }
  795. }
  796. internal Type CodeFileBaseClassType
  797. {
  798. get { return codeFileBaseClassType; }
  799. }
  800. internal List <UnknownAttributeDescriptor> UnknownMainAttributes
  801. {
  802. get { return unknownMainAttributes; }
  803. }
  804. #endif
  805. internal string Text {
  806. get { return text; }
  807. set { text = value; }
  808. }
  809. internal Type BaseType {
  810. get {
  811. if (baseType == null)
  812. SetBaseType (DefaultBaseTypeName);
  813. return baseType;
  814. }
  815. }
  816. internal bool BaseTypeIsGlobal {
  817. get { return baseTypeIsGlobal; }
  818. set { baseTypeIsGlobal = value; }
  819. }
  820. static long autoClassCounter = 0;
  821. static object autoClassCounterLock = new object ();
  822. internal string ClassName {
  823. get {
  824. if (className != null)
  825. return className;
  826. #if NET_2_0
  827. string physPath = HttpContext.Current.Request.PhysicalApplicationPath;
  828. string inFile;
  829. if (String.IsNullOrEmpty (inputFile)) {
  830. inFile = null;
  831. using (StreamReader sr = Reader as StreamReader) {
  832. if (sr != null) {
  833. FileStream fr = sr.BaseStream as FileStream;
  834. if (fr != null)
  835. inFile = fr.Name;
  836. }
  837. }
  838. } else
  839. inFile = inputFile;
  840. if (String.IsNullOrEmpty (inFile)) {
  841. // generate a unique class name
  842. long suffix;
  843. lock (autoClassCounterLock) {
  844. suffix = autoClassCounter++;
  845. }
  846. className = String.Format ("autoclass_nosource_{0:x}", suffix);
  847. return className;
  848. }
  849. if (StrUtils.StartsWith (inFile, physPath)) {
  850. className = inputFile.Substring (physPath.Length).ToLower (CultureInfo.InvariantCulture);
  851. className = className.Replace ('.', '_');
  852. className = className.Replace ('/', '_').Replace ('\\', '_');
  853. } else
  854. #endif
  855. className = Path.GetFileName (inputFile).Replace ('.', '_');
  856. className = className.Replace ('-', '_');
  857. className = className.Replace (' ', '_');
  858. if (Char.IsDigit(className[0])) {
  859. className = "_" + className;
  860. }
  861. return className;
  862. }
  863. }
  864. internal ArrayList Scripts {
  865. get {
  866. if (scripts == null)
  867. scripts = new ArrayList ();
  868. return scripts;
  869. }
  870. }
  871. internal ArrayList Imports {
  872. get { return imports; }
  873. }
  874. internal ArrayList Assemblies {
  875. get {
  876. if (appAssemblyIndex != -1) {
  877. object o = assemblies [appAssemblyIndex];
  878. assemblies.RemoveAt (appAssemblyIndex);
  879. assemblies.Add (o);
  880. appAssemblyIndex = -1;
  881. }
  882. return assemblies;
  883. }
  884. }
  885. internal ArrayList Interfaces {
  886. get { return interfaces; }
  887. }
  888. internal RootBuilder RootBuilder {
  889. get { return rootBuilder; }
  890. set { rootBuilder = value; }
  891. }
  892. internal ArrayList Dependencies {
  893. get { return dependencies; }
  894. set { dependencies = value; }
  895. }
  896. internal string CompilerOptions {
  897. get { return compilerOptions; }
  898. }
  899. internal string Language {
  900. get { return language; }
  901. }
  902. internal bool ImplicitLanguage {
  903. get { return implicitLanguage; }
  904. }
  905. internal bool StrictOn {
  906. get { return strictOn; }
  907. }
  908. internal bool ExplicitOn {
  909. get { return explicitOn; }
  910. }
  911. internal bool Debug {
  912. get { return debug; }
  913. }
  914. internal bool OutputCache {
  915. get { return output_cache; }
  916. }
  917. internal int OutputCacheDuration {
  918. get { return oc_duration; }
  919. }
  920. #if NET_2_0
  921. internal string OutputCacheVaryByContentEncodings {
  922. get { return oc_content_encodings; }
  923. }
  924. internal virtual TextReader Reader {
  925. get { return null; }
  926. set { /* no-op */ }
  927. }
  928. #endif
  929. internal string OutputCacheVaryByHeader {
  930. get { return oc_header; }
  931. }
  932. internal string OutputCacheVaryByCustom {
  933. get { return oc_custom; }
  934. }
  935. internal string OutputCacheVaryByControls {
  936. get { return oc_controls; }
  937. }
  938. internal bool OutputCacheShared {
  939. get { return oc_shared; }
  940. }
  941. internal OutputCacheLocation OutputCacheLocation {
  942. get { return oc_location; }
  943. }
  944. internal string OutputCacheVaryByParam {
  945. get { return oc_param; }
  946. }
  947. #if NET_2_0
  948. internal PagesSection PagesConfig {
  949. get {
  950. return WebConfigurationManager.GetSection ("system.web/pages") as PagesSection;
  951. }
  952. }
  953. #else
  954. internal PagesConfiguration PagesConfig {
  955. get { return PagesConfiguration.GetInstance (Context); }
  956. }
  957. #endif
  958. }
  959. }