2010-03-02 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Web / System.Web.UI / TemplateControl.cs
blob6dd55c0c8dea567882aa65165849e313a3d0460f
1 //
2 // System.Web.UI.TemplateControl.cs
3 //
4 // Authors:
5 // Duncan Mak (duncan@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 //
9 // (C) 2002 Ximian, Inc. (http://www.ximian.com)
10 // Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
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.
32 using System.Collections;
33 using System.ComponentModel;
34 using System.Reflection;
35 using System.Security.Permissions;
36 using System.Web.Compilation;
37 using System.Web.Util;
38 using System.Xml;
39 using System.IO;
40 using System.Runtime.InteropServices;
41 using System.Text;
43 namespace System.Web.UI
45 // CAS
46 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
48 public abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService
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 "Page_PreInit",
56 "Page_PreLoad",
57 "Page_LoadComplete",
58 "Page_PreRenderComplete",
59 "Page_SaveStateComplete",
60 "Page_InitComplete",
61 "Page_Load",
62 "Page_DataBind",
63 "Page_PreRender",
64 "Page_Disposed",
65 "Page_Error",
66 "Page_Unload",
67 "Page_AbortTransaction",
68 "Page_CommitTransaction"};
70 const BindingFlags bflags = BindingFlags.Public |
71 BindingFlags.NonPublic |
72 BindingFlags.Instance;
74 string _appRelativeVirtualPath;
75 StringResourceData resource_data;
77 #region Constructor
78 protected TemplateControl ()
80 TemplateControl = this;
81 Construct ();
84 #endregion
86 #region Properties
87 [EditorBrowsable (EditorBrowsableState.Never)]
88 [Obsolete]
89 protected virtual int AutoHandlers {
90 get { return 0; }
91 set { }
94 [EditorBrowsable (EditorBrowsableState.Never)]
95 protected virtual bool SupportAutoEvents {
96 get { return true; }
99 public string AppRelativeVirtualPath {
100 get { return _appRelativeVirtualPath; }
101 set { _appRelativeVirtualPath = value; }
104 #endregion
106 #region Methods
108 protected virtual void Construct ()
112 protected LiteralControl CreateResourceBasedLiteralControl (int offset, int size, bool fAsciiOnly)
114 if (resource_data == null)
115 return null;
117 if (offset > resource_data.MaxOffset - size)
118 throw new ArgumentOutOfRangeException ("size");
120 IntPtr ptr = AddOffset (resource_data.Ptr, offset);
121 return new ResourceBasedLiteralControl (ptr, size);
124 class EvtInfo {
125 public MethodInfo method;
126 public string methodName;
127 public EventInfo evt;
128 public bool noParams;
131 static Hashtable auto_event_info;
132 static object auto_event_info_monitor = new Object ();
134 internal void WireupAutomaticEvents ()
136 if (!SupportAutoEvents || !AutoEventWireup)
137 return;
139 ArrayList events = null;
141 /* Avoid expensive reflection operations by computing the event info only once */
142 lock (auto_event_info_monitor) {
143 if (auto_event_info == null)
144 auto_event_info = new Hashtable ();
145 events = (ArrayList)auto_event_info [GetType ()];
146 if (events == null) {
147 events = CollectAutomaticEventInfo ();
148 auto_event_info [GetType ()] = events;
152 for (int i = 0; i < events.Count; ++i) {
153 EvtInfo evinfo = (EvtInfo)events [i];
154 if (evinfo.noParams) {
155 NoParamsInvoker npi = new NoParamsInvoker (this, evinfo.method);
156 evinfo.evt.AddEventHandler (this, npi.FakeDelegate);
157 } else
158 evinfo.evt.AddEventHandler (this, Delegate.CreateDelegate (typeof (EventHandler), this, evinfo.method));
162 ArrayList CollectAutomaticEventInfo () {
163 ArrayList events = new ArrayList ();
165 foreach (string methodName in methodNames) {
166 MethodInfo method = null;
167 Type type;
168 for (type = GetType (); type.Assembly != _System_Web_Assembly; type = type.BaseType) {
169 method = type.GetMethod (methodName, bflags);
170 if (method != null)
171 break;
173 if (method == null)
174 continue;
176 if (method.DeclaringType != type) {
177 if (!method.IsPublic && !method.IsFamilyOrAssembly &&
178 !method.IsFamilyAndAssembly && !method.IsFamily)
179 continue;
182 if (method.ReturnType != typeof (void))
183 continue;
185 ParameterInfo [] parms = method.GetParameters ();
186 int length = parms.Length;
187 bool noParams = (length == 0);
188 if (!noParams && (length != 2 ||
189 parms [0].ParameterType != typeof (object) ||
190 parms [1].ParameterType != typeof (EventArgs)))
191 continue;
193 int pos = methodName.IndexOf ('_');
194 string eventName = methodName.Substring (pos + 1);
195 EventInfo evt = type.GetEvent (eventName);
196 if (evt == null) {
197 /* This should never happen */
198 continue;
201 EvtInfo evinfo = new EvtInfo ();
202 evinfo.method = method;
203 evinfo.methodName = methodName;
204 evinfo.evt = evt;
205 evinfo.noParams = noParams;
207 events.Add (evinfo);
210 return events;
213 [EditorBrowsable (EditorBrowsableState.Never)]
214 protected virtual void FrameworkInitialize ()
218 Type GetTypeFromControlPath (string virtualPath)
220 if (virtualPath == null)
221 throw new ArgumentNullException ("virtualPath");
223 string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
224 return BuildManager.GetCompiledType (vpath);
227 public Control LoadControl (string virtualPath)
229 if (virtualPath == null)
230 throw new ArgumentNullException ("virtualPath");
231 Type type = GetTypeFromControlPath (virtualPath);
233 return LoadControl (type, null);
236 public Control LoadControl (Type type, object[] parameters)
238 object [] attrs = null;
240 if (type != null)
241 type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
242 if (attrs != null && attrs.Length == 1) {
243 PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
244 PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
245 ctrl.VaryByParams = attr.VaryByParams;
246 ctrl.VaryByControls = attr.VaryByControls;
247 ctrl.VaryByCustom = attr.VaryByCustom;
248 return ctrl;
251 object control = Activator.CreateInstance (type, parameters);
252 if (control is UserControl)
253 ((UserControl) control).InitializeAsUserControl (Page);
255 return (Control) control;
258 public ITemplate LoadTemplate (string virtualPath)
260 if (virtualPath == null)
261 throw new ArgumentNullException ("virtualPath");
262 Type t = GetTypeFromControlPath (virtualPath);
263 return new SimpleTemplate (t);
266 protected virtual void OnAbortTransaction (EventArgs e)
268 EventHandler eh = Events [abortTransaction] as EventHandler;
269 if (eh != null)
270 eh (this, e);
273 protected virtual void OnCommitTransaction (EventArgs e)
275 EventHandler eh = Events [commitTransaction] as EventHandler;
276 if (eh != null)
277 eh (this, e);
280 protected virtual void OnError (EventArgs e)
282 EventHandler eh = Events [error] as EventHandler;
283 if (eh != null)
284 eh (this, e);
287 public Control ParseControl (string content)
289 if (content == null)
290 throw new ArgumentNullException ("content");
292 // FIXME: This method needs to be rewritten in some sane way - the way it is now,
293 // is a kludge. New version should not use
294 // UserControlParser.GetCompiledType, but instead resort to some other way
295 // of creating the content (template instantiation? BuildManager? TBD)
296 TextReader reader = new StringReader (content);
297 Type control = UserControlParser.GetCompiledType (reader, content.GetHashCode (), HttpContext.Current);
298 if (control == null)
299 return null;
301 TemplateControl parsedControl = Activator.CreateInstance (control, null) as TemplateControl;
302 if (parsedControl == null)
303 return null;
305 if (this is System.Web.UI.Page)
306 parsedControl.Page = (System.Web.UI.Page) this;
307 parsedControl.FrameworkInitialize ();
309 Control ret = new Control ();
310 int count = parsedControl.Controls.Count;
311 Control[] parsedControlControls = new Control [count];
312 parsedControl.Controls.CopyTo (parsedControlControls, 0);
314 for (int i = 0; i < count; i++)
315 ret.Controls.Add (parsedControlControls [i]);
317 parsedControl = null;
318 return ret;
321 [MonoTODO ("Parser filters not implemented yet. Calls ParseControl (string) for now.")]
322 public Control ParseControl (string content, bool ignoreParserFilter)
324 return ParseControl (content);
327 [EditorBrowsable (EditorBrowsableState.Never)]
328 public object ReadStringResource ()
330 return ReadStringResource (GetType ());
333 class StringResourceData {
334 public IntPtr Ptr;
335 public int Length;
336 public int MaxOffset;
339 protected object GetGlobalResourceObject (string className, string resourceKey)
341 return HttpContext.GetGlobalResourceObject (className, resourceKey);
344 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
346 if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) ||
347 String.IsNullOrEmpty (className) || objType == null)
348 return null;
350 object globalObject = GetGlobalResourceObject (className, resourceKey);
351 if (globalObject == null)
352 return null;
354 TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
355 if (converter == null || !converter.CanConvertFrom (globalObject.GetType ()))
356 return null;
358 return converter.ConvertFrom (globalObject);
361 protected object GetLocalResourceObject (string resourceKey)
363 return HttpContext.GetLocalResourceObject (VirtualPathUtility.ToAbsolute (this.AppRelativeVirtualPath),
364 resourceKey);
367 protected object GetLocalResourceObject (string resourceKey, Type objType, string propName)
369 if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) || objType == null)
370 return null;
372 object localObject = GetLocalResourceObject (resourceKey);
373 if (localObject == null)
374 return null;
376 TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
377 if (converter == null || !converter.CanConvertFrom (localObject.GetType ()))
378 return null;
380 return converter.ConvertFrom (localObject);
383 internal override TemplateControl TemplateControlInternal {
384 get { return this; }
387 [EditorBrowsable (EditorBrowsableState.Never)]
388 public static object ReadStringResource (Type t)
390 StringResourceData data = new StringResourceData ();
391 if (ICalls.GetUnmanagedResourcesPtr (t.Assembly, out data.Ptr, out data.Length))
392 return data;
394 throw new HttpException ("Unable to load the string resources.");
397 [EditorBrowsable (EditorBrowsableState.Never)]
398 protected void SetStringResourcePointer (object stringResourcePointer,
399 int maxResourceOffset)
401 StringResourceData rd = stringResourcePointer as StringResourceData;
402 if (rd == null)
403 return;
405 if (maxResourceOffset < 0 || maxResourceOffset > rd.Length)
406 throw new ArgumentOutOfRangeException ("maxResourceOffset");
408 resource_data = new StringResourceData ();
409 resource_data.Ptr = rd.Ptr;
410 resource_data.Length = rd.Length;
411 resource_data.MaxOffset = maxResourceOffset > 0 ? Math.Min (maxResourceOffset, rd.Length) : rd.Length;
414 static IntPtr AddOffset (IntPtr ptr, int offset)
416 if (offset == 0)
417 return ptr;
419 if (IntPtr.Size == 4) {
420 int p = ptr.ToInt32 () + offset;
421 ptr = new IntPtr (p);
422 } else {
423 long p = ptr.ToInt64 () + offset;
424 ptr = new IntPtr (p);
426 return ptr;
429 [EditorBrowsable (EditorBrowsableState.Never)]
430 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset, int size, bool fAsciiOnly)
432 if (resource_data == null)
433 return; // throw?
434 if (output == null)
435 throw new ArgumentNullException ("output");
436 if (offset > resource_data.MaxOffset - size)
437 throw new ArgumentOutOfRangeException ("size");
439 //TODO: fAsciiOnly?
440 IntPtr ptr = AddOffset (resource_data.Ptr, offset);
441 HttpWriter writer = output.GetHttpWriter ();
443 if (writer == null || writer.Response.ContentEncoding.CodePage != 65001) {
444 byte [] bytes = new byte [size];
445 Marshal.Copy (ptr, bytes, 0, size);
446 output.Write (Encoding.UTF8.GetString (bytes));
447 bytes = null;
448 return;
451 writer.WriteUTF8Ptr (ptr, size);
454 #endregion
456 #region Events
458 [WebSysDescription ("Raised when the user aborts a transaction.")]
459 public event EventHandler AbortTransaction {
460 add { Events.AddHandler (abortTransaction, value); }
461 remove { Events.RemoveHandler (abortTransaction, value); }
464 [WebSysDescription ("Raised when the user initiates a transaction.")]
465 public event EventHandler CommitTransaction {
466 add { Events.AddHandler (commitTransaction, value); }
467 remove { Events.RemoveHandler (commitTransaction, value); }
470 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
471 public event EventHandler Error {
472 add { Events.AddHandler (error, value); }
473 remove { Events.RemoveHandler (error, value); }
476 #endregion
478 class SimpleTemplate : ITemplate
480 Type type;
482 public SimpleTemplate (Type type)
484 this.type = type;
487 public void InstantiateIn (Control control)
489 Control template = Activator.CreateInstance (type) as Control;
490 template.SetBindingContainer (false);
491 control.Controls.Add (template);
495 protected internal object Eval (string expression)
497 return DataBinder.Eval (Page.GetDataItem(), expression);
500 protected internal string Eval (string expression, string format)
502 return DataBinder.Eval (Page.GetDataItem(), expression, format);
505 protected internal object XPath (string xpathexpression)
507 return XPathBinder.Eval (Page.GetDataItem(), xpathexpression);
510 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
512 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
515 protected internal string XPath (string xpathexpression, string format)
517 return XPathBinder.Eval (Page.GetDataItem(), xpathexpression, format);
520 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
522 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
525 protected internal IEnumerable XPathSelect (string xpathexpression)
527 return XPathBinder.Select (Page.GetDataItem(), xpathexpression);
530 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
532 return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
535 // IFilterResolutionService
537 [MonoTODO ("Not implemented")]
538 int IFilterResolutionService.CompareFilters (string filter1, string filter2)
540 throw new NotImplementedException ();
543 [MonoTODO ("Not implemented")]
544 bool IFilterResolutionService.EvaluateFilter (string filterName)
546 throw new NotImplementedException ();