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-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:
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
)]
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",
58 "Page_PreRenderComplete",
59 "Page_SaveStateComplete",
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
;
78 protected TemplateControl ()
80 TemplateControl
= this;
87 [EditorBrowsable (EditorBrowsableState
.Never
)]
89 protected virtual int AutoHandlers
{
94 [EditorBrowsable (EditorBrowsableState
.Never
)]
95 protected virtual bool SupportAutoEvents
{
99 public string AppRelativeVirtualPath
{
100 get { return _appRelativeVirtualPath; }
101 set { _appRelativeVirtualPath = value; }
108 protected virtual void Construct ()
112 protected LiteralControl
CreateResourceBasedLiteralControl (int offset
, int size
, bool fAsciiOnly
)
114 if (resource_data
== 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
);
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
)
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
);
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;
168 for (type
= GetType (); type
.Assembly
!= _System_Web_Assembly
; type
= type
.BaseType
) {
169 method
= type
.GetMethod (methodName
, bflags
);
176 if (method
.DeclaringType
!= type
) {
177 if (!method
.IsPublic
&& !method
.IsFamilyOrAssembly
&&
178 !method
.IsFamilyAndAssembly
&& !method
.IsFamily
)
182 if (method
.ReturnType
!= typeof (void))
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
)))
193 int pos
= methodName
.IndexOf ('_');
194 string eventName
= methodName
.Substring (pos
+ 1);
195 EventInfo evt
= type
.GetEvent (eventName
);
197 /* This should never happen */
201 EvtInfo evinfo
= new EvtInfo ();
202 evinfo
.method
= method
;
203 evinfo
.methodName
= methodName
;
205 evinfo
.noParams
= noParams
;
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;
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
;
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
;
273 protected virtual void OnCommitTransaction (EventArgs e
)
275 EventHandler eh
= Events
[commitTransaction
] as EventHandler
;
280 protected virtual void OnError (EventArgs e
)
282 EventHandler eh
= Events
[error
] as EventHandler
;
287 public Control
ParseControl (string content
)
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
);
301 TemplateControl parsedControl
= Activator
.CreateInstance (control
, null) as TemplateControl
;
302 if (parsedControl
== 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;
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
{
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)
350 object globalObject
= GetGlobalResourceObject (className
, resourceKey
);
351 if (globalObject
== null)
354 TypeConverter converter
= TypeDescriptor
.GetProperties (objType
) [propName
].Converter
;
355 if (converter
== null || !converter
.CanConvertFrom (globalObject
.GetType ()))
358 return converter
.ConvertFrom (globalObject
);
361 protected object GetLocalResourceObject (string resourceKey
)
363 return HttpContext
.GetLocalResourceObject (VirtualPathUtility
.ToAbsolute (this.AppRelativeVirtualPath
),
367 protected object GetLocalResourceObject (string resourceKey
, Type objType
, string propName
)
369 if (String
.IsNullOrEmpty (resourceKey
) || String
.IsNullOrEmpty (propName
) || objType
== null)
372 object localObject
= GetLocalResourceObject (resourceKey
);
373 if (localObject
== null)
376 TypeConverter converter
= TypeDescriptor
.GetProperties (objType
) [propName
].Converter
;
377 if (converter
== null || !converter
.CanConvertFrom (localObject
.GetType ()))
380 return converter
.ConvertFrom (localObject
);
383 internal override TemplateControl TemplateControlInternal
{
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
))
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
;
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
)
419 if (IntPtr
.Size
== 4) {
420 int p
= ptr
.ToInt32 () + offset
;
421 ptr
= new IntPtr (p
);
423 long p
= ptr
.ToInt64 () + offset
;
424 ptr
= new IntPtr (p
);
429 [EditorBrowsable (EditorBrowsableState
.Never
)]
430 protected void WriteUTF8ResourceString (HtmlTextWriter output
, int offset
, int size
, bool fAsciiOnly
)
432 if (resource_data
== null)
435 throw new ArgumentNullException ("output");
436 if (offset
> resource_data
.MaxOffset
- size
)
437 throw new ArgumentOutOfRangeException ("size");
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
));
451 writer
.WriteUTF8Ptr (ptr
, size
);
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); }
478 class SimpleTemplate
: ITemplate
482 public SimpleTemplate (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 ();