2 // System.Web.UI.TemplateControl.cs
5 // Duncan Mak (duncan@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
9 // (C) 2002 Ximian, Inc. (http://www.ximian.com)
10 // Copyright (C) 2005 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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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;
40 using System.Runtime.InteropServices;
43 namespace System.Web.UI {
46 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
47 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
49 public abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService {
51 public abstract class TemplateControl : Control, INamingContainer {
53 static readonly Assembly _System_Web_Assembly = typeof (TemplateControl).Assembly;
54 static object abortTransaction = new object ();
55 static object commitTransaction = new object ();
56 static object error = new object ();
57 static string [] methodNames = { "Page_Init",
62 "Page_PreRenderComplete",
63 "Page_SaveStateComplete",
72 "Page_AbortTransaction",
73 "Page_CommitTransaction"};
75 const BindingFlags bflags = BindingFlags.Public |
76 BindingFlags.NonPublic |
77 BindingFlags.Instance;
80 string _appRelativeVirtualPath;
82 StringResourceData resource_data;
85 protected TemplateControl ()
88 TemplateControl = this;
96 [EditorBrowsable (EditorBrowsableState.Never)]
100 protected virtual int AutoHandlers {
105 [EditorBrowsable (EditorBrowsableState.Never)]
106 protected virtual bool SupportAutoEvents {
111 public string AppRelativeVirtualPath {
112 get { return _appRelativeVirtualPath; }
113 set { _appRelativeVirtualPath = value; }
121 protected virtual void Construct ()
125 protected LiteralControl CreateResourceBasedLiteralControl (int offset, int size, bool fAsciiOnly)
127 if (resource_data == null)
130 if (offset > resource_data.MaxOffset - size)
131 throw new ArgumentOutOfRangeException ("size");
133 IntPtr ptr = AddOffset (resource_data.Ptr, offset);
134 return new ResourceBasedLiteralControl (ptr, size);
138 public MethodInfo method;
139 public string methodName;
140 public EventInfo evt;
141 public bool noParams;
144 static Hashtable auto_event_info;
145 static object auto_event_info_monitor = new Object ();
147 internal void WireupAutomaticEvents ()
149 if (!SupportAutoEvents || !AutoEventWireup)
152 ArrayList events = null;
154 /* Avoid expensive reflection operations by computing the event info only once */
155 lock (auto_event_info_monitor) {
156 if (auto_event_info == null)
157 auto_event_info = new Hashtable ();
158 events = (ArrayList)auto_event_info [GetType ()];
159 if (events == null) {
160 events = CollectAutomaticEventInfo ();
161 auto_event_info [GetType ()] = events;
165 for (int i = 0; i < events.Count; ++i) {
166 EvtInfo evinfo = (EvtInfo)events [i];
167 if (evinfo.noParams) {
168 NoParamsInvoker npi = new NoParamsInvoker (this, evinfo.method);
169 evinfo.evt.AddEventHandler (this, npi.FakeDelegate);
171 evinfo.evt.AddEventHandler (this, Delegate.CreateDelegate (
173 typeof (EventHandler), this, evinfo.method));
175 typeof (EventHandler), this, evinfo.methodName));
181 ArrayList CollectAutomaticEventInfo () {
182 ArrayList events = new ArrayList ();
184 foreach (string methodName in methodNames) {
185 MethodInfo method = null;
187 for (type = GetType (); type.Assembly != _System_Web_Assembly; type = type.BaseType) {
188 method = type.GetMethod (methodName, bflags);
195 if (method.DeclaringType != type) {
196 if (!method.IsPublic && !method.IsFamilyOrAssembly &&
197 !method.IsFamilyAndAssembly && !method.IsFamily)
201 if (method.ReturnType != typeof (void))
204 ParameterInfo [] parms = method.GetParameters ();
205 int length = parms.Length;
206 bool noParams = (length == 0);
207 if (!noParams && (length != 2 ||
208 parms [0].ParameterType != typeof (object) ||
209 parms [1].ParameterType != typeof (EventArgs)))
212 int pos = methodName.IndexOf ('_');
213 string eventName = methodName.Substring (pos + 1);
214 EventInfo evt = type.GetEvent (eventName);
216 /* This should never happen */
220 EvtInfo evinfo = new EvtInfo ();
221 evinfo.method = method;
222 evinfo.methodName = methodName;
224 evinfo.noParams = noParams;
232 [EditorBrowsable (EditorBrowsableState.Never)]
233 protected virtual void FrameworkInitialize ()
237 Type GetTypeFromControlPath (string virtualPath)
239 if (virtualPath == null)
240 throw new ArgumentNullException ("virtualPath");
242 string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
244 return BuildManager.GetCompiledType (vpath);
246 string realpath = Context.Request.MapPath (vpath);
247 return UserControlParser.GetCompiledType (vpath, realpath, Context);
251 public Control LoadControl (string virtualPath)
254 if (virtualPath == null)
255 throw new ArgumentNullException ("virtualPath");
257 if (virtualPath == null)
258 throw new HttpException ("virtualPath is null");
260 Type type = GetTypeFromControlPath (virtualPath);
262 return LoadControl (type, null);
265 public Control LoadControl (Type type, object[] parameters)
267 object [] attrs = null;
270 type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
271 if (attrs != null && attrs.Length == 1) {
272 PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
273 PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
274 ctrl.VaryByParams = attr.VaryByParams;
275 ctrl.VaryByControls = attr.VaryByControls;
276 ctrl.VaryByCustom = attr.VaryByCustom;
280 object control = Activator.CreateInstance (type, parameters);
281 if (control is UserControl)
282 ((UserControl) control).InitializeAsUserControl (Page);
284 return (Control) control;
287 public ITemplate LoadTemplate (string virtualPath)
290 if (virtualPath == null)
291 throw new ArgumentNullException ("virtualPath");
293 if (virtualPath == null)
294 throw new HttpException ("virtualPath is null");
296 Type t = GetTypeFromControlPath (virtualPath);
297 return new SimpleTemplate (t);
300 protected virtual void OnAbortTransaction (EventArgs e)
302 EventHandler eh = Events [abortTransaction] as EventHandler;
307 protected virtual void OnCommitTransaction (EventArgs e)
309 EventHandler eh = Events [commitTransaction] as EventHandler;
314 protected virtual void OnError (EventArgs e)
316 EventHandler eh = Events [error] as EventHandler;
322 [MonoTODO ("Not implemented, always returns null")]
324 public Control ParseControl (string content)
327 throw new ArgumentNullException ("content");
330 // FIXME: This method needs to be rewritten in some sane way - the way it is now,
331 // is a kludge. New version should not use
332 // UserControlParser.GetCompiledType, but instead resort to some other way
333 // of creating the content (template instantiation? BuildManager? TBD)
334 TextReader reader = new StringReader (content);
335 Type control = UserControlParser.GetCompiledType (reader, content.GetHashCode (), HttpContext.Current);
339 TemplateControl parsedControl = Activator.CreateInstance (control, null) as TemplateControl;
340 if (parsedControl == null)
343 if (this is System.Web.UI.Page)
344 parsedControl.Page = (System.Web.UI.Page) this;
345 parsedControl.FrameworkInitialize ();
347 Control ret = new Control ();
348 int count = parsedControl.Controls.Count;
349 Control[] parsedControlControls = new Control [count];
350 parsedControl.Controls.CopyTo (parsedControlControls, 0);
352 for (int i = 0; i < count; i++)
353 ret.Controls.Add (parsedControlControls [i]);
355 parsedControl = null;
363 [MonoTODO ("Parser filters not implemented yet. Calls ParseControl (string) for now.")]
364 public Control ParseControl (string content, bool ignoreParserFilter)
366 return ParseControl (content);
371 [EditorBrowsable (EditorBrowsableState.Never)]
372 public object ReadStringResource ()
374 return ReadStringResource (GetType ());
378 class StringResourceData {
381 public int MaxOffset;
385 protected object GetGlobalResourceObject (string className, string resourceKey)
387 return HttpContext.GetGlobalResourceObject (className, resourceKey);
390 protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
392 if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) ||
393 String.IsNullOrEmpty (className) || objType == null)
396 object globalObject = GetGlobalResourceObject (className, resourceKey);
397 if (globalObject == null)
400 TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
401 if (converter == null || !converter.CanConvertFrom (globalObject.GetType ()))
404 return converter.ConvertFrom (globalObject);
407 protected object GetLocalResourceObject (string resourceKey)
409 return HttpContext.GetLocalResourceObject (VirtualPathUtility.ToAbsolute (this.AppRelativeVirtualPath),
413 protected object GetLocalResourceObject (string resourceKey, Type objType, string propName)
415 if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) || objType == null)
418 object localObject = GetLocalResourceObject (resourceKey);
419 if (localObject == null)
422 TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
423 if (converter == null || !converter.CanConvertFrom (localObject.GetType ()))
426 return converter.ConvertFrom (localObject);
429 internal override TemplateControl TemplateControlInternal {
434 [EditorBrowsable (EditorBrowsableState.Never)]
435 public static object ReadStringResource (Type t)
437 StringResourceData data = new StringResourceData ();
438 if (ICalls.GetUnmanagedResourcesPtr (t.Assembly, out data.Ptr, out data.Length))
441 throw new HttpException ("Unable to load the string resources.");
444 [EditorBrowsable (EditorBrowsableState.Never)]
445 protected void SetStringResourcePointer (object stringResourcePointer,
446 int maxResourceOffset)
448 StringResourceData rd = stringResourcePointer as StringResourceData;
452 if (maxResourceOffset < 0 || maxResourceOffset > rd.Length)
453 throw new ArgumentOutOfRangeException ("maxResourceOffset");
455 resource_data = new StringResourceData ();
456 resource_data.Ptr = rd.Ptr;
457 resource_data.Length = rd.Length;
458 resource_data.MaxOffset = maxResourceOffset > 0 ? Math.Min (maxResourceOffset, rd.Length) : rd.Length;
461 static IntPtr AddOffset (IntPtr ptr, int offset)
466 if (IntPtr.Size == 4) {
467 int p = ptr.ToInt32 () + offset;
468 ptr = new IntPtr (p);
470 long p = ptr.ToInt64 () + offset;
471 ptr = new IntPtr (p);
476 [EditorBrowsable (EditorBrowsableState.Never)]
477 protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset, int size, bool fAsciiOnly)
479 if (resource_data == null)
482 throw new ArgumentNullException ("output");
483 if (offset > resource_data.MaxOffset - size)
484 throw new ArgumentOutOfRangeException ("size");
487 IntPtr ptr = AddOffset (resource_data.Ptr, offset);
488 HttpWriter writer = output.GetHttpWriter ();
489 if (writer == null || writer.Response.ContentEncoding.CodePage != 65001) {
490 byte [] bytes = new byte [size];
491 Marshal.Copy (ptr, bytes, 0, size);
492 writer.Write (Encoding.UTF8.GetString (bytes));
497 writer.WriteUTF8Ptr (ptr, size);
504 [WebSysDescription ("Raised when the user aborts a transaction.")]
505 public event EventHandler AbortTransaction {
506 add { Events.AddHandler (abortTransaction, value); }
507 remove { Events.RemoveHandler (abortTransaction, value); }
510 [WebSysDescription ("Raised when the user initiates a transaction.")]
511 public event EventHandler CommitTransaction {
512 add { Events.AddHandler (commitTransaction, value); }
513 remove { Events.RemoveHandler (commitTransaction, value); }
516 [WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
517 public event EventHandler Error {
518 add { Events.AddHandler (error, value); }
519 remove { Events.RemoveHandler (error, value); }
524 class SimpleTemplate : ITemplate
528 public SimpleTemplate (Type type)
533 public void InstantiateIn (Control control)
535 Control template = Activator.CreateInstance (type) as Control;
536 template.SetBindingContainer (false);
537 control.Controls.Add (template);
542 protected internal object Eval (string expression)
544 return DataBinder.Eval (Page.GetDataItem(), expression);
547 protected internal string Eval (string expression, string format)
549 return DataBinder.Eval (Page.GetDataItem(), expression, format);
552 protected internal object XPath (string xpathexpression)
554 return XPathBinder.Eval (Page.GetDataItem(), xpathexpression);
557 protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
559 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
562 protected internal string XPath (string xpathexpression, string format)
564 return XPathBinder.Eval (Page.GetDataItem(), xpathexpression, format);
567 protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
569 return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
572 protected internal IEnumerable XPathSelect (string xpathexpression)
574 return XPathBinder.Select (Page.GetDataItem(), xpathexpression);
577 protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
579 return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
582 // IFilterResolutionService
584 [MonoTODO ("Not implemented")]
585 int IFilterResolutionService.CompareFilters (string filter1, string filter2)
587 throw new NotImplementedException ();
590 [MonoTODO ("Not implemented")]
591 bool IFilterResolutionService.EvaluateFilter (string filterName)
593 throw new NotImplementedException ();