//
// System.Web.UI.TemplateControl.cs
//
// Authors:
// Duncan Mak (duncan@ximian.com)
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
// Andreas Nahr (ClassDevelopment@A-SoftTech.com)
//
// (C) 2002 Ximian, Inc. (http://www.ximian.com)
// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Collections;
using System.ComponentModel;
using System.Reflection;
using System.Security.Permissions;
using System.Web.Compilation;
using System.Web.Util;
using System.Xml;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace System.Web.UI{
// CAS
[AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
public abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService
{
static readonly Assembly _System_Web_Assembly = typeof (TemplateControl).Assembly;
static object abortTransaction = new object ();
static object commitTransaction = new object ();
static object error = new object ();
static string [] methodNames = { "Page_Init",
"Page_PreInit",
"Page_PreLoad",
"Page_LoadComplete",
"Page_PreRenderComplete",
"Page_SaveStateComplete",
"Page_InitComplete",
"Page_Load",
"Page_DataBind",
"Page_PreRender",
"Page_Disposed",
"Page_Error",
"Page_Unload",
"Page_AbortTransaction",
"Page_CommitTransaction"};
const BindingFlags bflags = BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance;
string _appRelativeVirtualPath;
StringResourceData resource_data;
#region Constructor
protected TemplateControl ()
{
TemplateControl = this;
Construct ();
}
#endregion
#region Properties
[EditorBrowsable (EditorBrowsableState.Never)]
[Obsolete]
protected virtual int AutoHandlers {
get { return 0; }
set { }
}
[EditorBrowsable (EditorBrowsableState.Never)]
protected virtual bool SupportAutoEvents {
get { return true; }
}
public string AppRelativeVirtualPath {
get { return _appRelativeVirtualPath; }
set { _appRelativeVirtualPath = value; }
}
#endregion
#region Methods
protected virtual void Construct ()
{
}
protected LiteralControl CreateResourceBasedLiteralControl (int offset, int size, bool fAsciiOnly)
{
if (resource_data == null)
return null;
if (offset > resource_data.MaxOffset - size)
throw new ArgumentOutOfRangeException ("size");
IntPtr ptr = AddOffset (resource_data.Ptr, offset);
return new ResourceBasedLiteralControl (ptr, size);
}
class EvtInfo {
public MethodInfo method;
public string methodName;
public EventInfo evt;
public bool noParams;
}
static Hashtable auto_event_info;
static object auto_event_info_monitor = new Object ();
internal void WireupAutomaticEvents ()
{
if (!SupportAutoEvents || !AutoEventWireup)
return;
ArrayList events = null;
/* Avoid expensive reflection operations by computing the event info only once */
lock (auto_event_info_monitor) {
if (auto_event_info == null)
auto_event_info = new Hashtable ();
events = (ArrayList)auto_event_info [GetType ()];
if (events == null) {
events = CollectAutomaticEventInfo ();
auto_event_info [GetType ()] = events;
}
}
for (int i = 0; i < events.Count; ++i) {
EvtInfo evinfo = (EvtInfo)events [i];
if (evinfo.noParams) {
NoParamsInvoker npi = new NoParamsInvoker (this, evinfo.method);
evinfo.evt.AddEventHandler (this, npi.FakeDelegate);
} else
evinfo.evt.AddEventHandler (this, Delegate.CreateDelegate (typeof (EventHandler), this, evinfo.method));
}
}
ArrayList CollectAutomaticEventInfo () {
ArrayList events = new ArrayList ();
foreach (string methodName in methodNames) {
MethodInfo method = null;
Type type;
for (type = GetType (); type.Assembly != _System_Web_Assembly; type = type.BaseType) {
method = type.GetMethod (methodName, bflags);
if (method != null)
break;
}
if (method == null)
continue;
if (method.DeclaringType != type) {
if (!method.IsPublic && !method.IsFamilyOrAssembly &&
!method.IsFamilyAndAssembly && !method.IsFamily)
continue;
}
if (method.ReturnType != typeof (void))
continue;
ParameterInfo [] parms = method.GetParameters ();
int length = parms.Length;
bool noParams = (length == 0);
if (!noParams && (length != 2 ||
parms [0].ParameterType != typeof (object) ||
parms [1].ParameterType != typeof (EventArgs)))
continue;
int pos = methodName.IndexOf ('_');
string eventName = methodName.Substring (pos + 1);
EventInfo evt = type.GetEvent (eventName);
if (evt == null) {
/* This should never happen */
continue;
}
EvtInfo evinfo = new EvtInfo ();
evinfo.method = method;
evinfo.methodName = methodName;
evinfo.evt = evt;
evinfo.noParams = noParams;
events.Add (evinfo);
}
return events;
}
[EditorBrowsable (EditorBrowsableState.Never)]
protected virtual void FrameworkInitialize ()
{
}
Type GetTypeFromControlPath (string virtualPath)
{
if (virtualPath == null)
throw new ArgumentNullException ("virtualPath");
string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
return BuildManager.GetCompiledType (vpath);
}
public Control LoadControl (string virtualPath)
{
if (virtualPath == null)
throw new ArgumentNullException ("virtualPath");
Type type = GetTypeFromControlPath (virtualPath);
return LoadControl (type, null);
}
public Control LoadControl (Type type, object[] parameters)
{
object [] attrs = null;
if (type != null)
type.GetCustomAttributes (typeof (PartialCachingAttribute), true);
if (attrs != null && attrs.Length == 1) {
PartialCachingAttribute attr = (PartialCachingAttribute) attrs [0];
PartialCachingControl ctrl = new PartialCachingControl (type, parameters);
ctrl.VaryByParams = attr.VaryByParams;
ctrl.VaryByControls = attr.VaryByControls;
ctrl.VaryByCustom = attr.VaryByCustom;
return ctrl;
}
object control = Activator.CreateInstance (type, parameters);
if (control is UserControl)
((UserControl) control).InitializeAsUserControl (Page);
return (Control) control;
}
public ITemplate LoadTemplate (string virtualPath)
{
if (virtualPath == null)
throw new ArgumentNullException ("virtualPath");
Type t = GetTypeFromControlPath (virtualPath);
return new SimpleTemplate (t);
}
protected virtual void OnAbortTransaction (EventArgs e)
{
EventHandler eh = Events [abortTransaction] as EventHandler;
if (eh != null)
eh (this, e);
}
protected virtual void OnCommitTransaction (EventArgs e)
{
EventHandler eh = Events [commitTransaction] as EventHandler;
if (eh != null)
eh (this, e);
}
protected virtual void OnError (EventArgs e)
{
EventHandler eh = Events [error] as EventHandler;
if (eh != null)
eh (this, e);
}
public Control ParseControl (string content)
{
if (content == null)
throw new ArgumentNullException ("content");
// FIXME: This method needs to be rewritten in some sane way - the way it is now,
// is a kludge. New version should not use
// UserControlParser.GetCompiledType, but instead resort to some other way
// of creating the content (template instantiation? BuildManager? TBD)
TextReader reader = new StringReader (content);
Type control = UserControlParser.GetCompiledType (reader, content.GetHashCode (), HttpContext.Current);
if (control == null)
return null;
TemplateControl parsedControl = Activator.CreateInstance (control, null) as TemplateControl;
if (parsedControl == null)
return null;
if (this is System.Web.UI.Page)
parsedControl.Page = (System.Web.UI.Page) this;
parsedControl.FrameworkInitialize ();
Control ret = new Control ();
int count = parsedControl.Controls.Count;
Control[] parsedControlControls = new Control [count];
parsedControl.Controls.CopyTo (parsedControlControls, 0);
for (int i = 0; i < count; i++)
ret.Controls.Add (parsedControlControls [i]);
parsedControl = null;
return ret;
}
[MonoTODO ("Parser filters not implemented yet. Calls ParseControl (string) for now.")]
public Control ParseControl (string content, bool ignoreParserFilter)
{
return ParseControl (content);
}
[EditorBrowsable (EditorBrowsableState.Never)]
public object ReadStringResource ()
{
return ReadStringResource (GetType ());
}
class StringResourceData {
public IntPtr Ptr;
public int Length;
public int MaxOffset;
}
protected object GetGlobalResourceObject (string className, string resourceKey)
{
return HttpContext.GetGlobalResourceObject (className, resourceKey);
}
protected object GetGlobalResourceObject (string className, string resourceKey, Type objType, string propName)
{
if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) ||
String.IsNullOrEmpty (className) || objType == null)
return null;
object globalObject = GetGlobalResourceObject (className, resourceKey);
if (globalObject == null)
return null;
TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
if (converter == null || !converter.CanConvertFrom (globalObject.GetType ()))
return null;
return converter.ConvertFrom (globalObject);
}
protected object GetLocalResourceObject (string resourceKey)
{
return HttpContext.GetLocalResourceObject (VirtualPathUtility.ToAbsolute (this.AppRelativeVirtualPath),
resourceKey);
}
protected object GetLocalResourceObject (string resourceKey, Type objType, string propName)
{
if (String.IsNullOrEmpty (resourceKey) || String.IsNullOrEmpty (propName) || objType == null)
return null;
object localObject = GetLocalResourceObject (resourceKey);
if (localObject == null)
return null;
TypeConverter converter = TypeDescriptor.GetProperties (objType) [propName].Converter;
if (converter == null || !converter.CanConvertFrom (localObject.GetType ()))
return null;
return converter.ConvertFrom (localObject);
}
internal override TemplateControl TemplateControlInternal {
get { return this; }
}
[EditorBrowsable (EditorBrowsableState.Never)]
public static object ReadStringResource (Type t)
{
StringResourceData data = new StringResourceData ();
if (ICalls.GetUnmanagedResourcesPtr (t.Assembly, out data.Ptr, out data.Length))
return data;
throw new HttpException ("Unable to load the string resources.");
}
[EditorBrowsable (EditorBrowsableState.Never)]
protected void SetStringResourcePointer (object stringResourcePointer,
int maxResourceOffset)
{
StringResourceData rd = stringResourcePointer as StringResourceData;
if (rd == null)
return;
if (maxResourceOffset < 0 || maxResourceOffset > rd.Length)
throw new ArgumentOutOfRangeException ("maxResourceOffset");
resource_data = new StringResourceData ();
resource_data.Ptr = rd.Ptr;
resource_data.Length = rd.Length;
resource_data.MaxOffset = maxResourceOffset > 0 ? Math.Min (maxResourceOffset, rd.Length) : rd.Length;
}
static IntPtr AddOffset (IntPtr ptr, int offset)
{
if (offset == 0)
return ptr;
if (IntPtr.Size == 4) {
int p = ptr.ToInt32 () + offset;
ptr = new IntPtr (p);
} else {
long p = ptr.ToInt64 () + offset;
ptr = new IntPtr (p);
}
return ptr;
}
[EditorBrowsable (EditorBrowsableState.Never)]
protected void WriteUTF8ResourceString (HtmlTextWriter output, int offset, int size, bool fAsciiOnly)
{
if (resource_data == null)
return; // throw?
if (output == null)
throw new ArgumentNullException ("output");
if (offset > resource_data.MaxOffset - size)
throw new ArgumentOutOfRangeException ("size");
//TODO: fAsciiOnly?
IntPtr ptr = AddOffset (resource_data.Ptr, offset);
HttpWriter writer = output.GetHttpWriter ();
if (writer == null || writer.Response.ContentEncoding.CodePage != 65001) {
byte [] bytes = new byte [size];
Marshal.Copy (ptr, bytes, 0, size);
output.Write (Encoding.UTF8.GetString (bytes));
bytes = null;
return;
}
writer.WriteUTF8Ptr (ptr, size);
}
#endregion
#region Events
[WebSysDescription ("Raised when the user aborts a transaction.")]
public event EventHandler AbortTransaction {
add { Events.AddHandler (abortTransaction, value); }
remove { Events.RemoveHandler (abortTransaction, value); }
}
[WebSysDescription ("Raised when the user initiates a transaction.")]
public event EventHandler CommitTransaction {
add { Events.AddHandler (commitTransaction, value); }
remove { Events.RemoveHandler (commitTransaction, value); }
}
[WebSysDescription ("Raised when an exception occurs that cannot be handled.")]
public event EventHandler Error {
add { Events.AddHandler (error, value); }
remove { Events.RemoveHandler (error, value); }
}
#endregion
class SimpleTemplate : ITemplate
{
Type type;
public SimpleTemplate (Type type)
{
this.type = type;
}
public void InstantiateIn (Control control)
{
Control template = Activator.CreateInstance (type) as Control;
template.SetBindingContainer (false);
control.Controls.Add (template);
}
}
protected internal object Eval (string expression)
{
return DataBinder.Eval (Page.GetDataItem(), expression);
}
protected internal string Eval (string expression, string format)
{
return DataBinder.Eval (Page.GetDataItem(), expression, format);
}
protected internal object XPath (string xpathexpression)
{
return XPathBinder.Eval (Page.GetDataItem(), xpathexpression);
}
protected internal object XPath (string xpathexpression, IXmlNamespaceResolver resolver)
{
return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, null, resolver);
}
protected internal string XPath (string xpathexpression, string format)
{
return XPathBinder.Eval (Page.GetDataItem(), xpathexpression, format);
}
protected internal string XPath (string xpathexpression, string format, IXmlNamespaceResolver resolver)
{
return XPathBinder.Eval (Page.GetDataItem (), xpathexpression, format, resolver);
}
protected internal IEnumerable XPathSelect (string xpathexpression)
{
return XPathBinder.Select (Page.GetDataItem(), xpathexpression);
}
protected internal IEnumerable XPathSelect (string xpathexpression, IXmlNamespaceResolver resolver)
{
return XPathBinder.Select (Page.GetDataItem (), xpathexpression, resolver);
}
// IFilterResolutionService
[MonoTODO ("Not implemented")]
int IFilterResolutionService.CompareFilters (string filter1, string filter2)
{
throw new NotImplementedException ();
}
[MonoTODO ("Not implemented")]
bool IFilterResolutionService.EvaluateFilter (string filterName)
{
throw new NotImplementedException ();
}
}
}
|