2
0

TemplateControl.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. //
  2. // System.Web.UI.TemplateControl.cs
  3. //
  4. // Authors:
  5. // Duncan Mak ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. // Andreas Nahr ([email protected])
  8. //
  9. // (C) 2002 Ximian, Inc. (http://www.ximian.com)
  10. // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System.Collections;
  32. using System.ComponentModel;
  33. using System.Reflection;
  34. using System.Security.Permissions;
  35. using System.Web.Compilation;
  36. using System.Web.Util;
  37. using System.Xml;
  38. using System.IO;
  39. using System.Runtime.InteropServices;
  40. using System.Text;
  41. namespace System.Web.UI {
  42. // CAS
  43. [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  44. [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
  45. #if NET_2_0
  46. public abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService {
  47. #else
  48. public abstract class TemplateControl : Control, INamingContainer {
  49. #endif
  50. static readonly Assembly _System_Web_Assembly = typeof (TemplateControl).Assembly;
  51. static object abortTransaction = new object ();
  52. static object commitTransaction = new object ();
  53. static object error = new object ();
  54. static string [] methodNames = { "Page_Init",
  55. #if NET_2_0
  56. "Page_PreInit",
  57. "Page_PreLoad",
  58. "Page_LoadComplete",
  59. "Page_PreRenderComplete",
  60. "Page_SaveStateComplete",
  61. "Page_InitComplete",
  62. #endif
  63. "Page_Load",
  64. "Page_DataBind",
  65. "Page_PreRender",
  66. "Page_Disposed",
  67. "Page_Error",
  68. "Page_Unload",
  69. "Page_AbortTransaction",
  70. "Page_CommitTransaction"};
  71. const BindingFlags bflags = BindingFlags.Public |
  72. BindingFlags.NonPublic |
  73. BindingFlags.Instance;
  74. #if NET_2_0
  75. string _appRelativeVirtualPath;
  76. #endif
  77. StringResourceData resource_data;
  78. #region Constructor
  79. protected TemplateControl ()
  80. {
  81. #if NET_2_0
  82. TemplateControl = this;
  83. #endif
  84. Construct ();
  85. }
  86. #endregion
  87. #region Properties
  88. [EditorBrowsable (EditorBrowsableState.Never)]
  89. #if NET_2_0
  90. [Obsolete]
  91. #endif
  92. protected virtual int AutoHandlers {
  93. get { return 0; }
  94. set { }
  95. }
  96. [EditorBrowsable (EditorBrowsableState.Never)]
  97. protected virtual bool SupportAutoEvents {
  98. get { return true; }
  99. }
  100. #if NET_2_0
  101. public string AppRelativeVirtualPath {
  102. get { return _appRelativeVirtualPath; }
  103. set { _appRelativeVirtualPath = value; }
  104. }
  105. #endif
  106. #endregion
  107. #region Methods
  108. protected virtual void Construct ()
  109. {
  110. }
  111. protected LiteralControl CreateResourceBasedLiteralControl (int offset, int size, bool fAsciiOnly)
  112. {
  113. if (resource_data == null)
  114. return null;
  115. if (offset > resource_data.MaxOffset - size)
  116. throw new ArgumentOutOfRangeException ("size");
  117. IntPtr ptr = AddOffset (resource_data.Ptr, offset);
  118. return new ResourceBasedLiteralControl (ptr, size);
  119. }
  120. class EvtInfo {
  121. public MethodInfo method;
  122. public string methodName;
  123. public EventInfo evt;
  124. public bool noParams;
  125. }
  126. static Hashtable auto_event_info;
  127. static object auto_event_info_monitor = new Object ();
  128. internal void WireupAutomaticEvents ()
  129. {
  130. if (!SupportAutoEvents || !AutoEventWireup)
  131. return;
  132. ArrayList events = null;
  133. /* Avoid expensive reflection operations by computing the event info only once */
  134. lock (auto_event_info_monitor) {
  135. if (auto_event_info == null)
  136. auto_event_info = new Hashtable ();
  137. events = (ArrayList)auto_event_info [GetType ()];
  138. if (events == null) {
  139. events = CollectAutomaticEventInfo ();
  140. auto_event_info [GetType ()] = events;
  141. }
  142. }
  143. for (int i = 0; i < events.Count; ++i) {
  144. EvtInfo evinfo = (EvtInfo)events [i];
  145. if (evinfo.noParams) {
  146. NoParamsInvoker npi = new NoParamsInvoker (this, evinfo.method);
  147. evinfo.evt.AddEventHandler (this, npi.FakeDelegate);
  148. } else {
  149. evinfo.evt.AddEventHandler (this, Delegate.CreateDelegate (
  150. #if NET_2_0
  151. typeof (EventHandler), this, evinfo.method));
  152. #else
  153. typeof (EventHandler), this, evinfo.methodName));
  154. #endif
  155. }
  156. }
  157. }
  158. ArrayList CollectAutomaticEventInfo () {
  159. ArrayList events = new ArrayList ();
  160. foreach (string methodName in methodNames) {
  161. MethodInfo method = null;
  162. Type type;
  163. for (type = GetType (); type.Assembly != _System_Web_Assembly; type = type.BaseType) {
  164. method = type.GetMethod (methodName, bflags);
  165. if (method != null)
  166. break;
  167. }
  168. if (method == null)
  169. continue;
  170. if (method.DeclaringType != type) {
  171. if (!method.IsPublic && !method.IsFamilyOrAssembly &&
  172. !method.IsFamilyAndAssembly && !method.IsFamily)
  173. continue;
  174. }
  175. if (method.ReturnType != typeof (void))
  176. continue;
  177. ParameterInfo [] parms = method.GetParameters ();
  178. int length = parms.Length;
  179. bool noParams = (length == 0);
  180. if (!noParams && (length != 2 ||
  181. parms [0].ParameterType != typeof (object) ||
  182. parms [1].ParameterType != typeof (EventArgs)))
  183. continue;
  184. int pos = methodName.IndexOf ('_');
  185. string eventName = methodName.Substring (pos + 1);
  186. EventInfo evt = type.GetEvent (eventName);
  187. if (evt == null) {
  188. /* This should never happen */
  189. continue;
  190. }
  191. EvtInfo evinfo = new EvtInfo ();
  192. evinfo.method = method;
  193. evinfo.methodName = methodName;
  194. evinfo.evt = evt;
  195. evinfo.noParams = noParams;
  196. events.Add (evinfo);
  197. }
  198. return events;
  199. }
  200. [EditorBrowsable (EditorBrowsableState.Never)]
  201. protected virtual void FrameworkInitialize ()
  202. {
  203. }
  204. Type GetTypeFromControlPath (string virtualPath)
  205. {
  206. if (virtualPath == null)
  207. throw new ArgumentNullException ("virtualPath");
  208. string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
  209. #if NET_2_0
  210. return BuildManager.GetCompiledType (vpath);
  211. #else
  212. string realpath = Context.Request.MapPath (vpath);
  213. return UserControlParser.GetCompiledType (vpath, realpath, Context);
  214. #endif
  215. }
  216. public Control LoadControl (string virtualPath)
  217. {
  218. #if NET_2_0
  219. if (virtualPath == null)
  220. throw new ArgumentNullException ("virtualPath");
  221. #else
  222. if (virtualPath == null)
  223. throw new HttpException ("virtualPath is null");
  224. #endif
  225. Type type = GetTypeFromControlPath (virtualPath);
  226. return LoadControl (type, null);
  227. }
  228. public Control LoadControl (Type type, object[] parameters)
  229. {
  230. object [] attrs = null;
  231. if (type != null)
  232. type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
  233. if (attrs != null && attrs.Length == 1) {
  234. PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
  235. PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
  236. ctrl.VaryByParams = attr.VaryByParams;
  237. ctrl.VaryByControls = attr.VaryByControls;
  238. ctrl.VaryByCustom = attr.VaryByCustom;
  239. return ctrl;
  240. }
  241. object control = Activator.CreateInstance (type, parameters);
  242. if (control is UserControl)
  243. ((UserControl) control).InitializeAsUserControl (Page);
  244. return (Control) control;
  245. }
  246. public ITemplate LoadTemplate (string virtualPath)
  247. {
  248. #if NET_2_0
  249. if (virtualPath == null)
  250. throw new ArgumentNullException ("virtualPath");
  251. #else
  252. if (virtualPath == null)
  253. throw new HttpException ("virtualPath is null");
  254. #endif
  255. Type t = GetTypeFromControlPath (virtualPath);
  256. return new SimpleTemplate (t);
  257. }
  258. protected virtual void OnAbortTransaction (EventArgs e)
  259. {
  260. EventHandler eh = Events [abortTransaction] as EventHandler;
  261. if (eh != null)
  262. eh (this, e);
  263. }
  264. protected virtual void OnCommitTransaction (EventArgs e)
  265. {
  266. EventHandler eh = Events [commitTransaction] as EventHandler;
  267. if (eh != null)
  268. eh (this, e);
  269. }
  270. protected virtual void OnError (EventArgs e)
  271. {
  272. EventHandler eh = Events [error] as EventHandler;
  273. if (eh != null)
  274. eh (this, e);
  275. }
  276. #if !NET_2_0
  277. [MonoTODO ("Not implemented, always returns null")]
  278. #endif
  279. public Control ParseControl (string content)
  280. {
  281. if (content == null)
  282. throw new ArgumentNullException ("content");
  283. #if NET_2_0
  284. // FIXME: This method needs to be rewritten in some sane way - the way it is now,
  285. // is a kludge. New version should not use
  286. // UserControlParser.GetCompiledType, but instead resort to some other way
  287. // of creating the content (template instantiation? BuildManager? TBD)
  288. TextReader reader = new StringReader (content);
  289. Type control = UserControlParser.GetCompiledType (reader, content.GetHashCode (), HttpContext.Current);
  290. if (control == null)
  291. return null;
  292. TemplateControl parsedControl = Activator.CreateInstance (control, null) as TemplateControl;
  293. if (parsedControl == null)
  294. return null;
  295. if (this is System.Web.UI.Page)
  296. parsedControl.Page = (System.Web.UI.Page) this;
  297. parsedControl.FrameworkInitialize ();
  298. Control ret = new Control ();
  299. int count = parsedControl.Controls.Count;
  300. Control[] parsedControlControls = new Control [count];
  301. parsedControl.Controls.CopyTo (parsedControlControls, 0);
  302. for (int i = 0; i < count; i++)
  303. ret.Controls.Add (parsedControlControls [i]);
  304. parsedControl = null;
  305. return ret;
  306. #else
  307. return null;
  308. #endif
  309. }
  310. #if NET_2_0
  311. [MonoTODO ("Parser filters not implemented yet. Calls ParseControl (string) for now.")]
  312. public Control ParseControl (string content, bool ignoreParserFilter)
  313. {
  314. return ParseControl (content);
  315. }
  316. #endif
  317. #if NET_2_0
  318. [EditorBrowsable (EditorBrowsableState.Never)]
  319. public object ReadStringResource ()
  320. {
  321. return ReadStringResource (GetType ());
  322. }
  323. #endif
  324. class StringResourceData {
  325. public IntPtr Ptr;
  326. public int Length;
  327. public int MaxOffset;
  328. }
  329. #if NET_2_0
  330. protected object GetGlobalResourceObject (string className, string resourceKey)
  331. {
  332. return HttpContext.GetGlobalResourceObject (className, resourceKey);
  333. }
  334. protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
  335. {
  336. if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) ||
  337. String.IsNullOrEmpty (className) || objType == null)
  338. return null;
  339. object globalObject = GetGlobalResourceObject (className, resourceKey);
  340. if (globalObject == null)
  341. return null;
  342. TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
  343. if (converter == null || !converter.CanConvertFrom (globalObject.GetType ()))
  344. return null;
  345. return converter.ConvertFrom (globalObject);
  346. }
  347. protected object GetLocalResourceObject (string resourceKey)
  348. {
  349. return HttpContext.GetLocalResourceObject (VirtualPathUtility.ToAbsolute (this.AppRelativeVirtualPath),
  350. resourceKey);
  351. }
  352. protected object GetLocalResourceObject (string resourceKey, Type objType, string propName)
  353. {
  354. if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) || objType == null)
  355. return null;
  356. object localObject = GetLocalResourceObject (resourceKey);
  357. if (localObject == null)
  358. return null;
  359. TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
  360. if (converter == null || !converter.CanConvertFrom (localObject.GetType ()))
  361. return null;
  362. return converter.ConvertFrom (localObject);
  363. }
  364. internal override TemplateControl TemplateControlInternal {
  365. get { return this; }
  366. }
  367. #endif
  368. [EditorBrowsable (EditorBrowsableState.Never)]
  369. public static object ReadStringResource (Type t)
  370. {
  371. StringResourceData data = new StringResourceData ();
  372. if (ICalls.GetUnmanagedResourcesPtr (t.Assembly, out data.Ptr, out data.Length))
  373. return data;
  374. throw new HttpException ("Unable to load the string resources.");
  375. }
  376. [EditorBrowsable (EditorBrowsableState.Never)]
  377. protected void SetStringResourcePointer (object stringResourcePointer,
  378. int maxResourceOffset)
  379. {
  380. StringResourceData rd = stringResourcePointer as StringResourceData;
  381. if (rd == null)
  382. return;
  383. if (maxResourceOffset < 0 || maxResourceOffset > rd.Length)
  384. throw new ArgumentOutOfRangeException ("maxResourceOffset");
  385. resource_data = new StringResourceData ();
  386. resource_data.Ptr = rd.Ptr;
  387. resource_data.Length = rd.Length;
  388. resource_data.MaxOffset = maxResourceOffset > 0 ? Math.Min (maxResourceOffset, rd.Length) : rd.Length;
  389. }
  390. static IntPtr AddOffset (IntPtr ptr, int offset)
  391. {
  392. if (offset == 0)
  393. return ptr;
  394. if (IntPtr.Size == 4) {
  395. int p = ptr.ToInt32 () + offset;
  396. ptr = new IntPtr (p);
  397. } else {
  398. long p = ptr.ToInt64 () + offset;
  399. ptr = new IntPtr (p);
  400. }
  401. return ptr;
  402. }
  403. [EditorBrowsable (EditorBrowsableState.Never)]
  404. protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset, int size, bool fAsciiOnly)
  405. {
  406. if (resource_data == null)
  407. return; // throw?
  408. if (output == null)
  409. throw new ArgumentNullException ("output");
  410. if (offset > resource_data.MaxOffset - size)
  411. throw new ArgumentOutOfRangeException ("size");
  412. //TODO: fAsciiOnly?
  413. IntPtr ptr = AddOffset (resource_data.Ptr, offset);
  414. HttpWriter writer = output.GetHttpWriter ();
  415. if (writer == null || writer.Response.ContentEncoding.CodePage != 65001) {
  416. byte [] bytes = new byte [size];
  417. Marshal.Copy (ptr, bytes, 0, size);
  418. output.Write (Encoding.UTF8.GetString (bytes));
  419. bytes = null;
  420. return;
  421. }
  422. writer.WriteUTF8Ptr (ptr, size);
  423. }
  424. #endregion
  425. #region Events
  426. [WebSysDescription ("Raised when the user aborts a transaction.")]
  427. public event EventHandler AbortTransaction {
  428. add { Events.AddHandler (abortTransaction, value); }
  429. remove { Events.RemoveHandler (abortTransaction, value); }
  430. }
  431. [WebSysDescription ("Raised when the user initiates a transaction.")]
  432. public event EventHandler CommitTransaction {
  433. add { Events.AddHandler (commitTransaction, value); }
  434. remove { Events.RemoveHandler (commitTransaction, value); }
  435. }
  436. [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
  437. public event EventHandler Error {
  438. add { Events.AddHandler (error, value); }
  439. remove { Events.RemoveHandler (error, value); }
  440. }
  441. #endregion
  442. class SimpleTemplate : ITemplate
  443. {
  444. Type type;
  445. public SimpleTemplate (Type type)
  446. {
  447. this.type = type;
  448. }
  449. public void InstantiateIn (Control control)
  450. {
  451. Control template = Activator.CreateInstance (type) as Control;
  452. template.SetBindingContainer (false);
  453. control.Controls.Add (template);
  454. }
  455. }
  456. #if NET_2_0
  457. protected internal object Eval (string expression)
  458. {
  459. return DataBinder.Eval (Page.GetDataItem(), expression);
  460. }
  461. protected internal string Eval (string expression, string format)
  462. {
  463. return DataBinder.Eval (Page.GetDataItem(), expression, format);
  464. }
  465. protected internal object XPath (string xpathexpression)
  466. {
  467. return XPathBinder.Eval (Page.GetDataItem(), xpathexpression);
  468. }
  469. protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
  470. {
  471. return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
  472. }
  473. protected internal string XPath (string xpathexpression, string format)
  474. {
  475. return XPathBinder.Eval (Page.GetDataItem(), xpathexpression, format);
  476. }
  477. protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
  478. {
  479. return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
  480. }
  481. protected internal IEnumerable XPathSelect (string xpathexpression)
  482. {
  483. return XPathBinder.Select (Page.GetDataItem(), xpathexpression);
  484. }
  485. protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
  486. {
  487. return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
  488. }
  489. // IFilterResolutionService
  490. [MonoTODO ("Not implemented")]
  491. int IFilterResolutionService.CompareFilters (string filter1, string filter2)
  492. {
  493. throw new NotImplementedException ();
  494. }
  495. [MonoTODO ("Not implemented")]
  496. bool IFilterResolutionService.EvaluateFilter (string filterName)
  497. {
  498. throw new NotImplementedException ();
  499. }
  500. #endif
  501. }
  502. }