TemplateParser.cs 27 KB

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