//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ /* * Page class definition * * Copyright (c) 1998 Microsoft Corporation */ namespace System.Web.UI { using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Configuration; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Web; using System.Web.Caching; using System.Web.Compilation; using System.Web.Util; using System.Xml; using Debug = System.Web.Util.Debug; /* * Base class for Pages and UserControls */ /// /// Provides the class and the class with a base set of functionality. /// public abstract class TemplateControl : Control, INamingContainer, IFilterResolutionService { // Used for the literal string optimization (reading strings from resource) private IntPtr _stringResourcePointer; private int _maxResourceOffset; private static object _lockObject = new object(); // Caches the list of auto-hookup methods for each compiled Type (Hashtable). // We use a Hashtable instead of the central Cache for optimal performance (VSWhidbey 479476) private static Hashtable _eventListCache = new Hashtable(); private static object _emptyEventSingleton = new EventList(); private VirtualPath _virtualPath; private IResourceProvider _resourceProvider; private const string _pagePreInitEventName = "Page_PreInit"; private const string _pageInitEventName = "Page_Init"; private const string _pageInitCompleteEventName = "Page_InitComplete"; private const string _pageLoadEventName = "Page_Load"; private const string _pagePreLoadEventName = "Page_PreLoad"; private const string _pageLoadCompleteEventName = "Page_LoadComplete"; private const string _pagePreRenderCompleteEventName = "Page_PreRenderComplete"; private const string _pagePreRenderCompleteAsyncEventName = "Page_PreRenderCompleteAsync"; private const string _pageDataBindEventName = "Page_DataBind"; private const string _pagePreRenderEventName = "Page_PreRender"; private const string _pageSaveStateCompleteEventName = "Page_SaveStateComplete"; private const string _pageUnloadEventName = "Page_Unload"; private const string _pageErrorEventName = "Page_Error"; private const string _pageAbortTransactionEventName = "Page_AbortTransaction"; private const string _onTransactionAbortEventName = "OnTransactionAbort"; private const string _pageCommitTransactionEventName = "Page_CommitTransaction"; private const string _onTransactionCommitEventName = "OnTransactionCommit"; private static IDictionary _eventObjects; // Used to implement no-compile pages/uc private BuildResultNoCompileTemplateControl _noCompileBuildResult; static TemplateControl() { _eventObjects = new Hashtable(16); _eventObjects.Add(_pagePreInitEventName, Page.EventPreInit); _eventObjects.Add(_pageInitEventName, EventInit); _eventObjects.Add(_pageInitCompleteEventName, Page.EventInitComplete); _eventObjects.Add(_pageLoadEventName, EventLoad); _eventObjects.Add(_pagePreLoadEventName, Page.EventPreLoad); _eventObjects.Add(_pageLoadCompleteEventName, Page.EventLoadComplete); _eventObjects.Add(_pagePreRenderCompleteEventName, Page.EventPreRenderComplete); _eventObjects.Add(_pageDataBindEventName, EventDataBinding); _eventObjects.Add(_pagePreRenderEventName, EventPreRender); _eventObjects.Add(_pageSaveStateCompleteEventName, Page.EventSaveStateComplete); _eventObjects.Add(_pageUnloadEventName, EventUnload); _eventObjects.Add(_pageErrorEventName, EventError); _eventObjects.Add(_pageAbortTransactionEventName, EventAbortTransaction); _eventObjects.Add(_onTransactionAbortEventName, EventAbortTransaction); _eventObjects.Add(_pageCommitTransactionEventName, EventCommitTransaction); _eventObjects.Add(_onTransactionCommitEventName, EventCommitTransaction); } protected TemplateControl() { Construct(); } /// /// Do construction time logic (ASURT 66166) /// protected virtual void Construct() {} private static readonly object EventCommitTransaction = new object(); /// /// Occurs when a user initiates a transaction. /// [ WebSysDescription(SR.Page_OnCommitTransaction) ] public event EventHandler CommitTransaction { add { Events.AddHandler(EventCommitTransaction, value); } remove { Events.RemoveHandler(EventCommitTransaction, value); } } /// /// Gets and sets a value indicating whether theme is enabled. /// [ Browsable(true) ] public override bool EnableTheming { get { return base.EnableTheming; } set { base.EnableTheming = value; } } /// /// Raises the event. You can use this method /// for any transaction processing logic in which your page or user control /// participates. /// protected virtual void OnCommitTransaction(EventArgs e) { EventHandler handler = (EventHandler)Events[EventCommitTransaction]; if (handler != null) handler(this, e); } private static readonly object EventAbortTransaction = new object(); /// /// Occurs when a user aborts a transaction. /// [ WebSysDescription(SR.Page_OnAbortTransaction) ] public event EventHandler AbortTransaction { add { Events.AddHandler(EventAbortTransaction, value); } remove { Events.RemoveHandler(EventAbortTransaction, value); } } /// /// Raises the event. /// protected virtual void OnAbortTransaction(EventArgs e) { EventHandler handler = (EventHandler)Events[EventAbortTransaction]; if (handler != null) handler(this, e); } // Page_Error related events/methods private static readonly object EventError = new object(); /// /// Occurs when an uncaught exception is thrown. /// [ WebSysDescription(SR.Page_ErrorDescription) ] public event EventHandler Error { add { Events.AddHandler(EventError, value); } remove { Events.RemoveHandler(EventError, value); } } /// /// Raises the event. /// /// protected virtual void OnError(EventArgs e) { EventHandler handler = (EventHandler)Events[EventError]; if (handler != null) handler(this, e); } /* * Receive a no-compile build result that we call during FrameworkInitialize */ internal void SetNoCompileBuildResult(BuildResultNoCompileTemplateControl noCompileBuildResult) { _noCompileBuildResult = noCompileBuildResult; } internal bool NoCompile { get { return _noCompileBuildResult != null; } } /* * Method sometime overidden by the generated sub classes. Users * should not override. */ /// /// /// Initializes the requested page. While this is sometimes /// overridden when the page is generated at runtime, you should not explicitly override this method. /// [EditorBrowsable(EditorBrowsableState.Never)] protected virtual void FrameworkInitialize() { // If it's non-compiled, perform the FrameworkInitialize logic. if (NoCompile) { if (!HttpRuntime.DisableProcessRequestInApplicationTrust) { // If PermitOnly was disabled in config, we call PermitOnly from here so that at least // the control tree creation is protected, as it always is for compiled pages (VSWhidbey 449666) if (HttpRuntime.NamedPermissionSet != null && !HttpRuntime.ProcessRequestInApplicationTrust) { HttpRuntime.NamedPermissionSet.PermitOnly(); } } _noCompileBuildResult.FrameworkInitialize(this); } } /* * This property is overriden by the generated classes (hence it cannot be internal) * If false, we don't do the HookUpAutomaticHandlers() magic. */ /// /// /// [To be supplied.] /// [EditorBrowsable(EditorBrowsableState.Never)] protected virtual bool SupportAutoEvents { get { return true; } } /* * Returns a pointer to the resource buffer, and the largest valid offset * in the buffer (for security reason) */ internal IntPtr StringResourcePointer { get { return _stringResourcePointer; } } internal int MaxResourceOffset { get { return _maxResourceOffset; } } // This method is now obsolete. Ideally, we should get rid of it altogether, but that // would be a breaking change (VSWhidbey 464430) // We now use the parameter-less override, which is simpler [EditorBrowsable(EditorBrowsableState.Never)] public static object ReadStringResource(Type t) { return StringResourceManager.ReadSafeStringResource(t); } [EditorBrowsable(EditorBrowsableState.Never)] public object ReadStringResource() { return StringResourceManager.ReadSafeStringResource(GetType()); } /// /// /// This method is called by the generated classes (hence it cannot be internal) /// protected LiteralControl CreateResourceBasedLiteralControl(int offset, int size, bool fAsciiOnly) { return new ResourceBasedLiteralControl(this, offset, size, fAsciiOnly); } /// /// /// This method is called by the generated classes (hence it cannot be internal) /// [EditorBrowsable(EditorBrowsableState.Never)] protected void SetStringResourcePointer(object stringResourcePointer, int maxResourceOffset) { // Ignore the passed in maxResourceOffset, which cannot be trusted. Instead, use // the resource size that we obtained from the resource (ASURT 122759) SafeStringResource ssr = (SafeStringResource) stringResourcePointer; _stringResourcePointer = ssr.StringResourcePointer; _maxResourceOffset = ssr.ResourceSize; } internal VirtualPath VirtualPath { get { return _virtualPath; } } [ EditorBrowsable(EditorBrowsableState.Advanced), Browsable(false) ] public string AppRelativeVirtualPath { get { return VirtualPath.GetAppRelativeVirtualPathString(TemplateControlVirtualPath); } set { // Set the TemplateSourceDirectory based on the VirtualPath this.TemplateControlVirtualPath = VirtualPath.CreateNonRelative(value); } } internal VirtualPath TemplateControlVirtualPath { get { return _virtualPath; } set { _virtualPath = value; // Set the TemplateSourceDirectory based on the VirtualPath this.TemplateControlVirtualDirectory = _virtualPath.Parent; } } /// /// Tests if a device filter applies to this request /// public virtual bool TestDeviceFilter(string filterName) { return(Context.Request.Browser.IsBrowser(filterName)); } /// /// /// This method is called by the generated classes (hence it cannot be internal) /// [EditorBrowsable(EditorBrowsableState.Never)] protected void WriteUTF8ResourceString(HtmlTextWriter output, int offset, int size, bool fAsciiOnly) { // Make sure we don't access invalid data checked { if (offset < 0 || size < 0 || offset + size > _maxResourceOffset) throw new ArgumentOutOfRangeException("offset"); } output.WriteUTF8ResourceString(StringResourcePointer, offset, size, fAsciiOnly); } /* * This method is overriden by the generated classes (hence it cannot be internal) */ /// /// /// [EditorBrowsable(EditorBrowsableState.Never)] [Obsolete("Use of this property is not recommended because it is no longer useful. http://go.microsoft.com/fwlink/?linkid=14202")] protected virtual int AutoHandlers { get { return 0;} set {} } internal override TemplateControl GetTemplateControl() { return this; } [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "See comment on GetDelegateInformationWithAssert.")] internal void HookUpAutomaticHandlers() { // Do nothing if auto-events are not supported if (!SupportAutoEvents) { return; } // Get the event list for this Type from our cache, if possible object o = _eventListCache[GetType()]; EventList eventList; // Try to find what handlers are implemented if not tried before if (o == null) { lock (_lockObject) { // Try the cache again, in case another thread took care of it o = (EventList)_eventListCache[GetType()]; if (o == null) { eventList = new EventList(); GetDelegateInformation(eventList); // Cannot find any known handlers. if (eventList.IsEmpty) { o = _emptyEventSingleton; } else { o = eventList; } // Cache it for next time _eventListCache[GetType()] = o; } } } // Don't do any thing if no known handlers are found. if (o == _emptyEventSingleton) { return; } eventList = (EventList)o; IDictionary syncEvents = eventList.SyncEvents; // Hook up synchronous events foreach (var entry in syncEvents) { string key = entry.Key; SyncEventMethodInfo info = entry.Value; Debug.Assert(_eventObjects[key] != null); bool eventExists = false; MethodInfo methodInfo = info.MethodInfo; Delegate eventDelegates = Events[_eventObjects[key]]; if (eventDelegates != null) { foreach (Delegate eventDelegate in eventDelegates.GetInvocationList()) { // Ignore if this method is already added to the events list. if (eventDelegate.Method.Equals(methodInfo)) { eventExists = true; break; } } } if (!eventExists) { // Create a new Calli delegate proxy IntPtr functionPtr = methodInfo.MethodHandle.GetFunctionPointer(); EventHandler handler = (new CalliEventHandlerDelegateProxy(this, functionPtr, info.IsArgless)).Handler; // Adds the delegate to events list. Events.AddHandler(_eventObjects[key], handler); } } // Hook up asynchronous events IDictionary asyncEvents = eventList.AsyncEvents; AsyncEventMethodInfo preRenderCompleteAsyncEvent; if (asyncEvents.TryGetValue(_pagePreRenderCompleteAsyncEventName, out preRenderCompleteAsyncEvent)) { Page page = (Page)this; // this event handler only exists for the Page type if (preRenderCompleteAsyncEvent.RequiresCancellationToken) { var handler = FastDelegateCreator>.BindTo(this, preRenderCompleteAsyncEvent.MethodInfo); page.RegisterAsyncTask(new PageAsyncTask(handler)); } else { var handler = FastDelegateCreator>.BindTo(this, preRenderCompleteAsyncEvent.MethodInfo); page.RegisterAsyncTask(new PageAsyncTask(handler)); } } } private void GetDelegateInformation(EventList eventList) { if (HttpRuntime.IsFullTrust) { GetDelegateInformationWithNoAssert(eventList); } else { GetDelegateInformationWithAssert(eventList); } } // Make sure we have reflection permission to discover the handlers (ASURT 105965) // Using this permission is bad practice; we should use RMA instead of full MemberAccess, // or we should force the instance methods to be public. But this is a legacy behavior // and we can't change it without breaking the world. [ReflectionPermission(SecurityAction.Assert, Flags = ReflectionPermissionFlag.MemberAccess)] [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "See comment above.")] private void GetDelegateInformationWithAssert(EventList eventList) { GetDelegateInformationWithNoAssert(eventList); } private void GetDelegateInformationWithNoAssert(EventList eventList) { IDictionary syncEventDictionary = eventList.SyncEvents; IDictionary asyncEventDictionary = eventList.AsyncEvents; if (this is Page) { /* SYNCHRONOUS - Page */ GetDelegateInformationFromSyncMethod(_pagePreInitEventName, syncEventDictionary); GetDelegateInformationFromSyncMethod(_pagePreLoadEventName, syncEventDictionary); GetDelegateInformationFromSyncMethod(_pageLoadCompleteEventName, syncEventDictionary); GetDelegateInformationFromSyncMethod(_pagePreRenderCompleteEventName, syncEventDictionary); GetDelegateInformationFromSyncMethod(_pageInitCompleteEventName, syncEventDictionary); GetDelegateInformationFromSyncMethod(_pageSaveStateCompleteEventName, syncEventDictionary); /* ASYNCHRONOUS - Page */ GetDelegateInformationFromAsyncMethod(_pagePreRenderCompleteAsyncEventName, asyncEventDictionary); } /* SYNCHRONOUS - Control */ GetDelegateInformationFromSyncMethod(_pageInitEventName, syncEventDictionary); GetDelegateInformationFromSyncMethod(_pageLoadEventName, syncEventDictionary); GetDelegateInformationFromSyncMethod(_pageDataBindEventName, syncEventDictionary); GetDelegateInformationFromSyncMethod(_pagePreRenderEventName, syncEventDictionary); GetDelegateInformationFromSyncMethod(_pageUnloadEventName, syncEventDictionary); GetDelegateInformationFromSyncMethod(_pageErrorEventName, syncEventDictionary); if (!GetDelegateInformationFromSyncMethod(_pageAbortTransactionEventName, syncEventDictionary)) { GetDelegateInformationFromSyncMethod(_onTransactionAbortEventName, syncEventDictionary); } if (!GetDelegateInformationFromSyncMethod(_pageCommitTransactionEventName, syncEventDictionary)) { GetDelegateInformationFromSyncMethod(_onTransactionCommitEventName, syncEventDictionary); } /* ASYNCHRONOUS - Control */ } private bool GetDelegateInformationFromAsyncMethod(string methodName, IDictionary dictionary) { // First, try to get a delegate to the single-parameter handler MethodInfo parameterfulMethod = GetInstanceMethodInfo(typeof(Func), methodName); if (parameterfulMethod != null) { dictionary[methodName] = new AsyncEventMethodInfo(parameterfulMethod, requiresCancellationToken: true); return true; } // If there isn't one, try the argless one MethodInfo parameterlessMethod = GetInstanceMethodInfo(typeof(Func), methodName); if (parameterlessMethod != null) { dictionary[methodName] = new AsyncEventMethodInfo(parameterlessMethod, requiresCancellationToken: false); return true; } return false; } private bool GetDelegateInformationFromSyncMethod(string methodName, IDictionary dictionary) { // First, try to get a delegate to the two parameter handler MethodInfo parameterfulMethod = GetInstanceMethodInfo(typeof(EventHandler), methodName); if (parameterfulMethod != null) { dictionary[methodName] = new SyncEventMethodInfo(parameterfulMethod, isArgless: false); return true; } // If there isn't one, try the argless one MethodInfo parameterlessMethod = GetInstanceMethodInfo(typeof(VoidMethod), methodName); if (parameterlessMethod != null) { dictionary[methodName] = new SyncEventMethodInfo(parameterlessMethod, isArgless: true); return true; } return false; } private MethodInfo GetInstanceMethodInfo(Type delegateType, string methodName) { Delegate del = Delegate.CreateDelegate( type: delegateType, target: this, method: methodName, ignoreCase: true, throwOnBindFailure: false); return (del != null) ? del.Method : null; } /// /// Obtains a object from a user control file. /// public Control LoadControl(string virtualPath) { return LoadControl(VirtualPath.Create(virtualPath)); } internal Control LoadControl(VirtualPath virtualPath) { // If it's relative, make it *app* relative. Treat is as relative to this // user control (ASURT 55513) virtualPath = VirtualPath.Combine(this.TemplateControlVirtualDirectory, virtualPath); // Process the user control and get its BuildResult BuildResult result = BuildManager.GetVPathBuildResult(Context, virtualPath); return LoadControl((IWebObjectFactory)result, virtualPath, null /*Type*/, null /*parameters*/); } // Make sure we have reflection permission to use GetMethod below (ASURT 106196) [ReflectionPermission(SecurityAction.Assert, Flags=ReflectionPermissionFlag.MemberAccess)] private void AddStackContextToHashCode(HashCodeCombiner combinedHashCode) { StackTrace st = new StackTrace(); // First, skip all the stack frames that are in the TemplateControl class, as // they are irrelevant to the hash. Start the search at 2 since we know for sure // that this method and its caller are in TemplateControl. int startingUserFrame = 2; for (; ; startingUserFrame++) { StackFrame f = st.GetFrame(startingUserFrame); if (f.GetMethod().DeclaringType != typeof(TemplateControl)) { break; } } // Get a cache key based on the top two items of the caller's stack. // It's not guaranteed unique, but for all common cases, it will be for (int i = startingUserFrame; i < startingUserFrame + 2; i++) { StackFrame f = st.GetFrame(i); MethodBase m = f.GetMethod(); combinedHashCode.AddObject(m.DeclaringType.AssemblyQualifiedName); combinedHashCode.AddObject(m.Name); combinedHashCode.AddObject(f.GetNativeOffset()); } } public Control LoadControl(Type t, object[] parameters) { return LoadControl(null /*IWebObjectFactory*/, null /*virtualPath*/, t, parameters); } private Control LoadControl(IWebObjectFactory objectFactory, VirtualPath virtualPath, Type t, object[] parameters) { // Make sure we get an object factory or a type, but not both Debug.Assert((objectFactory == null) != (t == null)); BuildResultCompiledType compiledUCResult = null; BuildResultNoCompileUserControl noCompileUCResult = null; if (objectFactory != null) { // It can be a compiled or no-compile user control compiledUCResult = objectFactory as BuildResultCompiledType; if (compiledUCResult != null) { t = compiledUCResult.ResultType; Debug.Assert(t != null); // Make sure it's a user control (VSWhidbey 428718) Util.CheckAssignableType(typeof(UserControl), t); } else { noCompileUCResult = (BuildResultNoCompileUserControl)objectFactory; Debug.Assert(noCompileUCResult != null); } } else { // Make sure the type has the correct base class (ASURT 123677) if (t != null) Util.CheckAssignableType(typeof(Control), t); } PartialCachingAttribute cacheAttrib; // Check if the user control has a PartialCachingAttribute attribute if (t != null) { cacheAttrib = (PartialCachingAttribute) TypeDescriptor.GetAttributes(t)[typeof(PartialCachingAttribute)]; } else { cacheAttrib = noCompileUCResult.CachingAttribute; } if (cacheAttrib == null) { // The control is not cached. Just create it. Control c; if (objectFactory != null) { c = (Control) objectFactory.CreateInstance(); } else { c = (Control) HttpRuntime.CreatePublicInstance(t, parameters); } // If it's a user control, do some extra initialization UserControl uc = c as UserControl; if (uc != null) { Debug.Assert(virtualPath != null); if (virtualPath != null) uc.TemplateControlVirtualPath = virtualPath; uc.InitializeAsUserControl(Page); } return c; } HashCodeCombiner combinedHashCode = new HashCodeCombiner(); // Start by adding the type or object factory of the user control to the hash. // This guarantees that two unrelated user controls don't share the same cached data. if (objectFactory != null) { combinedHashCode.AddObject(objectFactory); } else { combinedHashCode.AddObject(t); } // If it's not shared, add some stack frames to the hash if (!cacheAttrib.Shared) { AddStackContextToHashCode(combinedHashCode); } string cacheKey = combinedHashCode.CombinedHashString; // Wrap it to allow it to be cached return new PartialCachingControl(objectFactory, t, cacheAttrib, "_" + cacheKey, parameters); } // Class that implements the templates returned by LoadTemplate (ASURT 94138) internal class SimpleTemplate : ITemplate { private IWebObjectFactory _objectFactory; internal SimpleTemplate(ITypedWebObjectFactory objectFactory) { // Make sure it's a user control (VSWhidbey 428718) Util.CheckAssignableType(typeof(UserControl), objectFactory.InstantiatedType); _objectFactory = objectFactory; } public virtual void InstantiateIn(Control control) { UserControl uc = (UserControl)_objectFactory.CreateInstance(); uc.InitializeAsUserControl(control.Page); control.Controls.Add(uc); } } /// /// /// Obtains an instance of the interface from an /// external file. /// /// public ITemplate LoadTemplate(string virtualPath) { return LoadTemplate(VirtualPath.Create(virtualPath)); } internal ITemplate LoadTemplate(VirtualPath virtualPath) { // If it's relative, make it *app* relative. Treat is as relative to this // user control (ASURT 55513) virtualPath = VirtualPath.Combine(TemplateControlVirtualDirectory, virtualPath); // Compile the declarative template and get its object factory ITypedWebObjectFactory objectFactory = (ITypedWebObjectFactory)BuildManager.GetVPathBuildResult( Context, virtualPath); return new SimpleTemplate(objectFactory); } /// /// Parse the input string into a Control. Looks for the first control /// in the input. Returns null if none is found. /// public Control ParseControl(string content) { return ParseControl(content, true); } public Control ParseControl(string content, bool ignoreParserFilter) { return TemplateParser.ParseControl(content, VirtualPath.Create(AppRelativeVirtualPath), ignoreParserFilter); } #if NOTYET /// /// Parse the input string into an ITemplate. /// internal ITemplate ParseTemplate(string content) { return TemplateParser.ParseTemplate(content, AppRelativeTemplateSourceDirectory); } #endif /// /// Used by simplified databinding methods to ensure they can only be called when the control is on a page. /// private void CheckPageExists() { if (Page == null) { throw new InvalidOperationException(SR.GetString(SR.TemplateControl_DataBindingRequiresPage)); } } /// /// Simplified databinding Eval() method. This method uses the current data item to evaluate an expression using DataBinder.Eval(). /// The data item is retrieved using either the IDataItemContainer interface or by looking for a property called 'DataItem'. /// If the data item is not found, an exception is thrown. /// protected internal object Eval(string expression) { CheckPageExists(); return DataBinder.Eval(Page.GetDataItem(), expression); } /// /// Simplified databinding Eval() method with a format expression. This method uses the current data item to evaluate an expression using DataBinder.Eval(). /// The data item is retrieved using either the IDataItemContainer interface or by looking for a property called 'DataItem'. /// If the data item is not found, an exception is thrown. /// protected internal string Eval(string expression, string format) { CheckPageExists(); return DataBinder.Eval(Page.GetDataItem(), expression, format); } /// /// Simplified databinding XPath() method. This method uses the current data item to evaluate an XPath expression using XPathBinder.Eval(). /// The data item is retrieved using either the IDataItemContainer interface or by looking for a property called 'DataItem'. /// If the data item is not found, an exception is thrown. /// protected internal object XPath(string xPathExpression) { CheckPageExists(); return XPathBinder.Eval(Page.GetDataItem(), xPathExpression); } /// /// Simplified databinding XPath() method. This method uses the current data item and a namespace resolver /// to evaluate an XPath expression using XPathBinder.Eval(). /// The data item is retrieved using either the IDataItemContainer interface or by looking for a property called 'DataItem'. /// If the data item is not found, an exception is thrown. /// protected internal object XPath(string xPathExpression, IXmlNamespaceResolver resolver) { CheckPageExists(); return XPathBinder.Eval(Page.GetDataItem(), xPathExpression, resolver); } /// /// Simplified databinding XPath() method with a format expression. This method uses the current data item to evaluate an XPath expression using XPathBinder.Eval(). /// The data item is retrieved using either the IDataItemContainer interface or by looking for a property called 'DataItem'. /// If the data item is not found, an exception is thrown. /// protected internal string XPath(string xPathExpression, string format) { CheckPageExists(); return XPathBinder.Eval(Page.GetDataItem(), xPathExpression, format); } /// /// Simplified databinding XPath() method with a format expression. This method uses the current data item and a namespace resolver /// to evaluate an XPath expression using XPathBinder.Eval(). /// The data item is retrieved using either the IDataItemContainer interface or by looking for a property called 'DataItem'. /// If the data item is not found, an exception is thrown. /// protected internal string XPath(string xPathExpression, string format, IXmlNamespaceResolver resolver) { CheckPageExists(); return XPathBinder.Eval(Page.GetDataItem(), xPathExpression, format, resolver); } /// /// Simplified databinding XPathSelect() method. This method uses the current data item to evaluate an XPath expression that returns a node list using XPathBinder.Select(). /// The data item is retrieved using either the IDataItemContainer interface or by looking for a property called 'DataItem'. /// If the data item is not found, an exception is thrown. /// protected internal IEnumerable XPathSelect(string xPathExpression) { CheckPageExists(); return XPathBinder.Select(Page.GetDataItem(), xPathExpression); } /// /// Simplified databinding XPathSelect() method. This method uses the current data item and a namespace resolver /// to evaluate an XPath expression that returns a node list using XPathBinder.Select(). /// The data item is retrieved using either the IDataItemContainer interface or by looking for a property called 'DataItem'. /// If the data item is not found, an exception is thrown. /// protected internal IEnumerable XPathSelect(string xPathExpression, IXmlNamespaceResolver resolver) { CheckPageExists(); return XPathBinder.Select(Page.GetDataItem(), xPathExpression, resolver); } /// /// Return a Page-level resource object /// protected object GetLocalResourceObject(string resourceKey) { // Cache the resource provider in the template control, so that if a Page needs to call // this multiple times, we don't need to call ResourceExpressionBuilder.GetLocalResourceProvider // every time. if (_resourceProvider == null) _resourceProvider = ResourceExpressionBuilder.GetLocalResourceProvider(this); return ResourceExpressionBuilder.GetResourceObject(_resourceProvider, resourceKey, null /*culture*/); } protected object GetLocalResourceObject(string resourceKey, Type objType, string propName) { // Cache the resource provider in the template control, so that if a Page needs to call // this multiple times, we don't need to call ResourceExpressionBuilder.GetLocalResourceProvider // every time. if (_resourceProvider == null) _resourceProvider = ResourceExpressionBuilder.GetLocalResourceProvider(this); return ResourceExpressionBuilder.GetResourceObject(_resourceProvider, resourceKey, null /*culture*/, objType, propName); } /// /// Return an App-level resource object /// protected object GetGlobalResourceObject(string className, string resourceKey) { return ResourceExpressionBuilder.GetGlobalResourceObject(className, resourceKey, null, null, null); } protected object GetGlobalResourceObject(string className, string resourceKey, Type objType, string propName) { return ResourceExpressionBuilder.GetGlobalResourceObject(className, resourceKey, objType, propName, null); } #region IFilterResolutionService /// bool IFilterResolutionService.EvaluateFilter(string filterName) { return TestDeviceFilter(filterName); } /// int IFilterResolutionService.CompareFilters(string filter1, string filter2) { return BrowserCapabilitiesCompiler.BrowserCapabilitiesFactory.CompareFilters(filter1, filter2); } #endregion private class EventList { internal readonly IDictionary AsyncEvents = new Dictionary(StringComparer.Ordinal); internal readonly IDictionary SyncEvents = new Dictionary(StringComparer.Ordinal); internal bool IsEmpty { get { return (AsyncEvents.Count == 0 && SyncEvents.Count == 0); } } } // Internal helper class for storing the event info private class SyncEventMethodInfo { internal SyncEventMethodInfo(MethodInfo methodInfo, bool isArgless){ if (IsAsyncVoidMethod(methodInfo)) { SynchronizationContextUtil.ValidateModeForPageAsyncVoidMethods(); } MethodInfo = methodInfo; IsArgless = isArgless; } internal bool IsArgless { get; private set; } internal MethodInfo MethodInfo { get; private set; } private static bool IsAsyncVoidMethod(MethodInfo methodInfo) { // When the C# / VB compilers generate an 'async void' method, they'll put // an [AsyncStateMachine] attribute on the entry point. This marker attribute // can be used to detect these methods. It's not 100% reliable, since it's // possible that a normal void method simply calls an async void method, and // the 'outer' method won't contain this attribute. But the heuristic is // good enough to help developers land in the pit of success re: async. return methodInfo.IsDefined(typeof(AsyncStateMachineAttribute), inherit: false); } } private class AsyncEventMethodInfo { internal AsyncEventMethodInfo(MethodInfo methodInfo, bool requiresCancellationToken) { MethodInfo = methodInfo; RequiresCancellationToken = requiresCancellationToken; } internal MethodInfo MethodInfo { get; private set; } internal bool RequiresCancellationToken { get; private set; } } } }