TemplateParser.cs 29 KB

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