Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
1 contributor

Users who have contributed to this file

6514 lines (5531 sloc) 255 KB
//------------------------------------------------------------------------------
// <copyright file="Page.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// Uncomment out this line to display rare field statistics at the end of the page
//#define DISPLAYRAREFIELDSTATISTICS
/*
* Page class definition
*
* Copyright (c) 1998 Microsoft Corporation
*/
namespace System.Web.UI {
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Configuration;
using System.EnterpriseServices;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Caching;
using System.Web.Compilation;
using System.Web.Configuration;
using System.Web.Handlers;
using System.Web.Hosting;
using System.Web.Management;
using System.Web.RegularExpressions;
using System.Web.Security;
using System.Web.SessionState;
using System.Web.UI.Adapters;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.Util;
using System.Xml;
using System.Web.Routing;
using System.Web.ModelBinding;
using System.Web.Security.Cryptography;
using System.Diagnostics.CodeAnalysis;
/// <devdoc>
/// Default ControlBuilder used to parse page files.
/// </devdoc>
public class FileLevelPageControlBuilder: RootBuilder {
private ArrayList _contentBuilderEntries;
private ControlBuilder _firstControlBuilder;
private int _firstLiteralLineNumber;
private bool _containsContentPage;
private string _firstLiteralText;
internal ICollection ContentBuilderEntries {
get {
return _contentBuilderEntries;
}
}
public override void AppendLiteralString(string text) {
if (_firstLiteralText == null) {
if (!Util.IsWhiteSpaceString(text)) {
int iFirstNonWhiteSpace = Util.FirstNonWhiteSpaceIndex(text);
if (iFirstNonWhiteSpace < 0) iFirstNonWhiteSpace = 0;
_firstLiteralLineNumber = Parser._lineNumber - Util.LineCount(text, iFirstNonWhiteSpace, text.Length);
_firstLiteralText = text;
if (_containsContentPage) {
throw new HttpException(SR.GetString(SR.Only_Content_supported_on_content_page));
}
}
}
base.AppendLiteralString(text);
}
public override void AppendSubBuilder(ControlBuilder subBuilder) {
// Tell the sub builder that it's about to be appended to its parent
if (subBuilder is ContentBuilderInternal) {
ContentBuilderInternal contentBuilder = (ContentBuilderInternal)subBuilder;
_containsContentPage = true;
if (_contentBuilderEntries == null) {
_contentBuilderEntries = new ArrayList();
}
if (_firstLiteralText != null) {
throw new HttpParseException(SR.GetString(SR.Only_Content_supported_on_content_page),
null, Parser.CurrentVirtualPath, _firstLiteralText, _firstLiteralLineNumber);
}
if (_firstControlBuilder != null) {
Parser._lineNumber = _firstControlBuilder.Line;
throw new HttpException(SR.GetString(SR.Only_Content_supported_on_content_page));
}
TemplatePropertyEntry entry = new TemplatePropertyEntry();
entry.Filter = contentBuilder.ContentPlaceHolderFilter;
entry.Name = contentBuilder.ContentPlaceHolder;
entry.Builder = contentBuilder;
_contentBuilderEntries.Add(entry);
}
else {
if (_firstControlBuilder == null) {
if (_containsContentPage) {
throw new HttpException(SR.GetString(SR.Only_Content_supported_on_content_page));
}
_firstControlBuilder = subBuilder;
}
}
base.AppendSubBuilder(subBuilder);
}
internal override void InitObject(object obj) {
base.InitObject(obj);
if (_contentBuilderEntries == null)
return;
ICollection entries = GetFilteredPropertyEntrySet(_contentBuilderEntries);
foreach(TemplatePropertyEntry entry in entries) {
ContentBuilderInternal contentBuilder = (ContentBuilderInternal)entry.Builder;
try {
contentBuilder.SetServiceProvider(ServiceProvider);
// Note that 'obj' can be either a Page or a MasterPage,
// hence the need for this virtual method.
AddContentTemplate(obj, contentBuilder.ContentPlaceHolder, contentBuilder.BuildObject() as ITemplate);
}
finally {
contentBuilder.SetServiceProvider(null);
}
}
}
internal virtual void AddContentTemplate(object obj, string templateName, ITemplate template) {
Page page = (Page)obj;
page.AddContentTemplate(templateName, template);
}
internal override void SortEntries() {
base.SortEntries();
FilteredPropertyEntryComparer comparer = null;
ProcessAndSortPropertyEntries(_contentBuilderEntries, ref comparer);
}
}
/// <devdoc>
/// <para>
/// Defines the properties, methods, and events common to
/// all pages that are processed on the server by the Web Forms page framework.
/// <see langword='Page '/>
/// objects are compiled and cached in
/// memory when any ASP.NET page is
/// requested.</para>
/// <para>This class is not marked as abstract, because the VS designer
/// needs to instantiate it when opening .ascx files</para>
/// </devdoc>
[
DefaultEvent("Load"),
Designer("Microsoft.VisualStudio.Web.WebForms.WebFormDesigner, " + AssemblyRef.MicrosoftVisualStudioWeb, typeof(IRootDesigner)),
DesignerCategory("ASPXCodeBehind"),
DesignerSerializer("Microsoft.VisualStudio.Web.WebForms.WebFormCodeDomSerializer, " + AssemblyRef.MicrosoftVisualStudioWeb, "System.ComponentModel.Design.Serialization.TypeCodeDomSerializer, " + AssemblyRef.SystemDesign),
ToolboxItem(false)
]
public class Page: TemplateControl, IHttpHandler {
private const string HiddenClassName = "aspNetHidden";
private const string PageID = "__Page";
private const string PageScrollPositionScriptKey = "PageScrollPositionScript";
private const string PageSubmitScriptKey = "PageSubmitScript";
private const string PageReEnableControlsScriptKey = "PageReEnableControlsScript";
// NOTE: Make sure this stays in sync with MobilePage.PageRegisteredControlsThatRequirePostBackKey
//
private const string PageRegisteredControlsThatRequirePostBackKey = "__ControlsRequirePostBackKey__";
private const string EnabledControlArray = "__enabledControlArray";
//used by TemplateControl to hookup auto-events
internal static readonly object EventPreRenderComplete = new Object();
internal static readonly object EventPreLoad = new object();
internal static readonly object EventLoadComplete = new object();
internal static readonly object EventPreInit = new object();
internal static readonly object EventInitComplete = new object();
internal static readonly object EventSaveStateComplete = new object();
private static readonly Version FocusMinimumEcmaVersion = new Version("1.4");
private static readonly Version FocusMinimumJScriptVersion = new Version("3.0");
private static readonly Version JavascriptMinimumVersion = new Version("1.0");
private static readonly Version MSDomScrollMinimumVersion = new Version("4.0");
// Review: this is consistent with MMIT legacy -do we prefer two underscores?
private static readonly string UniqueFilePathSuffixID = "__ufps";
private string _uniqueFilePathSuffix;
internal static readonly int DefaultMaxPageStateFieldLength = -1;
internal static readonly int DefaultAsyncTimeoutSeconds = 45;
private int _maxPageStateFieldLength = DefaultMaxPageStateFieldLength;
private string _requestViewState;
private bool _cachedRequestViewState;
private PageAdapter _pageAdapter;
// Has the page layout changed since last request
private bool _fPageLayoutChanged;
private bool _haveIdSeparator;
private char _idSeparator;
// Session state
private bool _sessionRetrieved;
private HttpSessionState _session;
private int _transactionMode; /* 0 = TransactionOption.Disabled*/
private bool _aspCompatMode;
private bool _asyncMode;
// Async related
private static readonly TimeSpan _maxAsyncTimeout = TimeSpan.FromMilliseconds(Int32.MaxValue);
private TimeSpan _asyncTimeout;
private bool _asyncTimeoutSet;
private PageAsyncTaskManager _asyncTaskManager;
private LegacyPageAsyncTaskManager _legacyAsyncTaskManager;
private LegacyPageAsyncInfo _legacyAsyncInfo;
// Page culture and uiculture set dynamically
private CultureInfo _dynamicCulture;
private CultureInfo _dynamicUICulture;
// ViewState
private string _clientState;
private PageStatePersister _persister;
internal ControlSet _registeredControlsRequiringControlState;
private StringSet _controlStateLoadedControlIds;
internal HybridDictionary _registeredControlsRequiringClearChildControlState;
internal const ViewStateEncryptionMode EncryptionModeDefault = ViewStateEncryptionMode.Auto;
private ViewStateEncryptionMode _encryptionMode = EncryptionModeDefault;
private bool _viewStateEncryptionRequested;
private ArrayList _enabledControls;
// Http Intrinsics
internal HttpRequest _request;
internal HttpResponse _response;
internal HttpApplicationState _application;
internal Cache _cache;
internal string _errorPage;
private string _clientTarget;
// Form related fields
private HtmlForm _form;
private bool _inOnFormRender;
private bool _fOnFormRenderCalled;
private bool _fRequireWebFormsScript;
private bool _fWebFormsScriptRendered;
private bool _fRequirePostBackScript;
private bool _fPostBackScriptRendered;
private bool _containsCrossPagePost;
private RenderMethod _postFormRenderDelegate;
internal Dictionary<String, String> _hiddenFieldsToRender;
private bool _requireFocusScript;
private bool _profileTreeBuilt;
internal const bool MaintainScrollPositionOnPostBackDefault = false;
private bool _maintainScrollPosition = MaintainScrollPositionOnPostBackDefault;
private ClientScriptManager _clientScriptManager;
// Needed to support Validators in AJAX 1.0 (Windows OS Bugs 2015831)
private static Type _scriptManagerType;
internal const bool EnableViewStateMacDefault = true;
internal const bool EnableEventValidationDefault = true;
internal const string systemPostFieldPrefix = "__";
/// <internalonly/>
[EditorBrowsable(EditorBrowsableState.Never)]
public const string postEventSourceID = systemPostFieldPrefix + "EVENTTARGET";
private const string lastFocusID = systemPostFieldPrefix + "LASTFOCUS";
private const string _scrollPositionXID = systemPostFieldPrefix + "SCROLLPOSITIONX";
private const string _scrollPositionYID = systemPostFieldPrefix + "SCROLLPOSITIONY";
/// <internalonly/>
[EditorBrowsable(EditorBrowsableState.Never)]
public const string postEventArgumentID = systemPostFieldPrefix + "EVENTARGUMENT";
internal const string ViewStateFieldPrefixID = systemPostFieldPrefix + "VIEWSTATE";
internal const string ViewStateFieldCountID = ViewStateFieldPrefixID + "FIELDCOUNT";
internal const string ViewStateGeneratorFieldID = ViewStateFieldPrefixID + "GENERATOR";
internal const string ViewStateEncryptionID = systemPostFieldPrefix + "VIEWSTATEENCRYPTED";
internal const string EventValidationPrefixID = systemPostFieldPrefix + "EVENTVALIDATION";
// Any change in this constant must be duplicated in DetermineIsExportingWebPart
internal const string WebPartExportID = systemPostFieldPrefix + "WEBPARTEXPORT";
private bool _requireScrollScript;
private bool _isCallback;
private bool _isCrossPagePostBack;
private bool _containsEncryptedViewState;
private bool _enableEventValidation = EnableEventValidationDefault;
internal const string callbackID = systemPostFieldPrefix + "CALLBACKID";
internal const string callbackParameterID = systemPostFieldPrefix + "CALLBACKPARAM";
internal const string callbackLoadScriptID = systemPostFieldPrefix + "CALLBACKLOADSCRIPT";
internal const string callbackIndexID = systemPostFieldPrefix + "CALLBACKINDEX";
internal const string previousPageID = systemPostFieldPrefix + "PREVIOUSPAGE";
// BasePartialCachingControl's currently on the stack
private Stack _partialCachingControlStack;
private ArrayList _controlsRequiringPostBack;
private ArrayList _registeredControlsThatRequirePostBack;
private NameValueCollection _leftoverPostData;
private IPostBackEventHandler _registeredControlThatRequireRaiseEvent;
private ArrayList _changedPostDataConsumers;
private bool _needToPersistViewState;
private bool _enableViewStateMac;
private string _viewStateUserKey;
private string _themeName;
private PageTheme _theme;
private string _styleSheetName;
private PageTheme _styleSheet;
private VirtualPath _masterPageFile;
private MasterPage _master;
private IDictionary _contentTemplateCollection;
private SmartNavigationSupport _smartNavSupport;
internal HttpContext _context;
private ValidatorCollection _validators;
private bool _validated;
private HtmlHead _header;
private int _supportsStyleSheets;
private Control _autoPostBackControl;
private string _focusedControlID;
private Control _focusedControl;
private string _validatorInvalidControl;
private int _scrollPositionX;
private int _scrollPositionY;
private Page _previousPage;
private VirtualPath _previousPagePath;
private bool _preInitWorkComplete;
private bool _clientSupportsJavaScriptChecked;
private bool _clientSupportsJavaScript;
private string _titleToBeSet;
private string _descriptionToBeSet;
private string _keywordsToBeSet;
private ICallbackEventHandler _callbackControl;
// DevDiv 33149, 43258: A backward compat. switch for Everett rendering,
private bool _xhtmlConformanceModeSet;
private XhtmlConformanceMode _xhtmlConformanceMode;
// const masks into the BitVector32
private const int styleSheetInitialized = 0x00000001;
private const int isExportingWebPart = 0x00000002;
private const int isExportingWebPartShared = 0x00000004;
private const int isCrossPagePostRequest = 0x00000008;
// Needed to support Validators in AJAX 1.0 (Windows OS Bugs 2015831)
private const int isPartialRenderingSupported = 0x00000010;
private const int isPartialRenderingSupportedSet = 0x00000020;
private const int skipFormActionValidation = 0x00000040;
private const int wasViewStateMacErrorSuppressed = 0x00000080;
// Todo: Move boolean fields into _pageFlags.
#pragma warning disable 0649
private SimpleBitVector32 _pageFlags;
#pragma warning restore 0649
// Can be either Context.Request.Form or Context.Request.QueryString
// depending on the method used.
private NameValueCollection _requestValueCollection;
// The unvalidated version of _requestValueCollection
private NameValueCollection _unvalidatedRequestValueCollection;
private ModelStateDictionary _modelState;
private ModelBindingExecutionContext _modelBindingExecutionContext;
private UnobtrusiveValidationMode? _unobtrusiveValidationMode;
private bool _executingAsyncTasks = false;
private static StringSet s_systemPostFields;
static Page() {
// Create a static hashtable with all the names that should be
// ignored in ProcessPostData().
s_systemPostFields = new StringSet();
s_systemPostFields.Add(postEventSourceID);
s_systemPostFields.Add(postEventArgumentID);
s_systemPostFields.Add(ViewStateFieldCountID);
s_systemPostFields.Add(ViewStateGeneratorFieldID);
s_systemPostFields.Add(ViewStateFieldPrefixID);
s_systemPostFields.Add(ViewStateEncryptionID);
s_systemPostFields.Add(previousPageID);
s_systemPostFields.Add(callbackID);
s_systemPostFields.Add(callbackParameterID);
s_systemPostFields.Add(lastFocusID);
s_systemPostFields.Add(UniqueFilePathSuffixID);
s_systemPostFields.Add(HttpResponse.RedirectQueryStringVariable);
s_systemPostFields.Add(EventValidationPrefixID);
}
/// <devdoc>
/// <para>Initializes a new instance of the <see cref='System.Web.UI.Page'/> class.</para>
/// </devdoc>
public Page() {
_page = this; // Set the page to ourselves
_enableViewStateMac = EnableViewStateMacDefault;
// Ensure that the page has an ID, for things like trace
ID = PageID;
_supportsStyleSheets = -1;
// Set the default ValidateRequestMode of a page to Enabled since the value Inherit
// does not make sense as the page has nobody to inherit from.
// Also, since this is the default value for Page, we do not want this value to be
// stored in ViewState , so we set the value here but do not set the property changed
// flag so that it's not stored in ViewState by default.
SetValidateRequestModeInternal(ValidateRequestMode.Enabled, setDirty: false);
}
public ModelStateDictionary ModelState {
get {
if (_modelState == null) {
_modelState = new ModelStateDictionary();
}
return _modelState;
}
}
private IValueProvider ActiveValueProvider {
get;
set;
}
internal bool IsExecutingAsyncTasks {
get {
return _executingAsyncTasks;
}
set {
_executingAsyncTasks = value;
}
}
public ModelBindingExecutionContext ModelBindingExecutionContext {
get {
if (_modelBindingExecutionContext == null) {
_modelBindingExecutionContext = new ModelBindingExecutionContext(new HttpContextWrapper(Context), this.ModelState);
//This is used to query the ViewState in ViewStateValueProvider later.
_modelBindingExecutionContext.PublishService<StateBag>(ViewState);
//This is used to query RouteData in RouteDataValueProvider later.
_modelBindingExecutionContext.PublishService<RouteData>(RouteData);
}
return _modelBindingExecutionContext;
}
}
/// <summary>
/// We support calling TryUpdateModel only within a Data Method of DataBoundControl.
/// So this method provides a way to enfore that.
/// This sets the active value provider which is used to provide the values for
/// TryUpdateModel. This method should be called before calling TryUpdateModel otherwise the latter
/// would throw. Also it's callers responsibility to reset the active value Provider by calling this
/// method again with null values. (Currently this is all done by ModelDataSourceView).
/// </summary>
internal void SetActiveValueProvider(IValueProvider valueProvider) {
ActiveValueProvider = valueProvider;
}
/// <summary>
/// Attempts to update the model object from the values within a databound control. This
/// must be invoked within the Select/Update/Delete/InsertMethods used for data binding.
/// </summary>
/// <returns>True if the model object is updated succesfully with valid values. False otherwise.</returns>
public virtual bool TryUpdateModel<TModel>(TModel model) where TModel : class {
if (ActiveValueProvider == null) {
throw new InvalidOperationException(SR.GetString(SR.Page_InvalidUpdateModelAttempt, "TryUpdateModel"));
}
return TryUpdateModel<TModel>(model, ActiveValueProvider);
}
/// <summary>
/// Attempts to update the model object from the values provided by given valueProvider.
/// </summary>
/// <returns>True if the model object is updated succesfully with valid values. False otherwise.</returns>
public virtual bool TryUpdateModel<TModel>(TModel model, IValueProvider valueProvider) where TModel : class {
if (model == null) {
throw new ArgumentNullException("model");
}
if (valueProvider == null) {
throw new ArgumentNullException("valueProvider");
}
IModelBinder binder = ModelBinders.Binders.DefaultBinder;
ModelBindingContext bindingContext = new ModelBindingContext() {
ModelBinderProviders = ModelBinderProviders.Providers,
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(TModel)),
ModelState = ModelState,
ValueProvider = valueProvider
};
if (binder.BindModel(ModelBindingExecutionContext, bindingContext)) {
return ModelState.IsValid;
}
//ModelBinding failed!!!
return false;
}
/// <summary>
/// Updates the model object from the values within a databound control. This must be invoked
/// within the Select/Update/Delete/InsertMethods used for data binding.
/// Throws an exception if the update fails.
/// </summary>
public virtual void UpdateModel<TModel>(TModel model) where TModel : class {
if (ActiveValueProvider == null) {
throw new InvalidOperationException(SR.GetString(SR.Page_InvalidUpdateModelAttempt, "UpdateModel"));
}
UpdateModel<TModel>(model, ActiveValueProvider);
}
/// <summary>
/// Updates the model object from the values provided by given valueProvider.
/// Throws an exception if the update fails.
/// </summary>
public virtual void UpdateModel<TModel>(TModel model, IValueProvider valueProvider) where TModel : class {
if (!TryUpdateModel(model, valueProvider)) {
throw new InvalidOperationException(SR.GetString(SR.Page_UpdateModel_UpdateUnsuccessful, typeof(TModel).FullName));
}
}
[
DefaultValue(UnobtrusiveValidationMode.None),
WebCategory("Behavior"),
WebSysDescription(SR.Page_UnobtrusiveValidationMode)
]
public UnobtrusiveValidationMode UnobtrusiveValidationMode {
get {
return _unobtrusiveValidationMode ?? ValidationSettings.UnobtrusiveValidationMode;
}
set {
if (value < UnobtrusiveValidationMode.None || value > UnobtrusiveValidationMode.WebForms) {
throw new ArgumentOutOfRangeException("value");
}
_unobtrusiveValidationMode = value;
}
}
/// <devdoc>
/// <para>Gets the <see langword='Application'/> object provided by the HTTP Runtime.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public HttpApplicationState Application {
get {
return _application;
}
}
/// <devdoc>
/// <para>Gets the HttpContext for the Page.</para>
/// </devdoc>
protected internal override HttpContext Context {
get {
if (_context == null) {
_context = HttpContext.Current;
}
return _context;
}
}
// Set of unique control ids which have already loaded control state
private StringSet ControlStateLoadedControlIds {
get {
if (_controlStateLoadedControlIds == null) {
_controlStateLoadedControlIds = new StringSet();
}
return _controlStateLoadedControlIds;
}
}
/// <devdoc>
/// The value to be written to the __VIEWSTATE hidden fields. Getter is exposed through a protected property in
/// PageAdapter.
/// </devdoc>
internal string ClientState {
get {
return _clientState;
}
set {
_clientState = value;
}
}
/*
* Any onsubmit statment to hook up by the form. The HtmlForm object calls this
* during RenderAttributes.
*/
internal string ClientOnSubmitEvent {
get {
if (ClientScript.HasSubmitStatements ||
(Form != null && Form.SubmitDisabledControls && (EnabledControls.Count > 0))) {
// to avoid being affected by earlier instructions we must
// write out the language as well
return "javascript:return WebForm_OnSubmit();";
}
return string.Empty;
}
}
public ClientScriptManager ClientScript {
get {
if (_clientScriptManager == null) {
_clientScriptManager = new ClientScriptManager(this);
}
return _clientScriptManager;
}
}
/// <devdoc>
/// <para>Indicates whether the requesting browser is uplevel or downlevel so that the appropriate behavior can be
/// generated for the request.</para>
/// </devdoc>
[
DefaultValue(""),
WebSysDescription(SR.Page_ClientTarget),
Browsable(false),
EditorBrowsable(EditorBrowsableState.Advanced),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public string ClientTarget {
get {
return (_clientTarget == null) ? String.Empty : _clientTarget;
}
set {
_clientTarget = value;
if (_request != null) {
_request.ClientTarget = value;
}
}
}
private string _clientQueryString = null;
public String ClientQueryString {
get {
if (_clientQueryString == null) {
if (RequestInternal != null && Request.HasQueryString) {
// Eliminate system post fields (generated by the framework) from the
// querystring used for adaptive rendering.
Hashtable ht = new Hashtable();
foreach (string systemPostField in s_systemPostFields) {
ht.Add(systemPostField, true);
}
//
HttpValueCollection httpValueCollection = (HttpValueCollection)((SkipFormActionValidation) ? Request.Unvalidated.QueryString : Request.QueryString);
_clientQueryString = httpValueCollection.ToString(urlencoded: true, excludeKeys: ht);
}
else {
_clientQueryString = String.Empty;
}
}
return _clientQueryString;
}
}
internal bool ContainsEncryptedViewState {
get {
return _containsEncryptedViewState;
}
set {
_containsEncryptedViewState = value;
}
}
/// <devdoc>
/// <para>
/// Gets or sets the error page to which the requesting browser should be
/// redirected in the event of an unhandled page exception.
/// </para>
/// </devdoc>
[
DefaultValue(""),
WebSysDescription(SR.Page_ErrorPage),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public string ErrorPage {
get {
return _errorPage;
}
set {
_errorPage = value;
}
}
/// <devdoc>
/// Gets a value indicating whether the page is being loaded in response to a client callback.
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public bool IsCallback {
get {
return _isCallback;
}
}
/// <internalonly/>
/// <devdoc>Page class can be cached/reused</devdoc>
[
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never)
]
public bool IsReusable {
get { return false; }
}
/// <devdoc>
/// Required for small browsers that cache too aggressively.
/// </devdoc>
protected internal virtual String UniqueFilePathSuffix {
get {
if (_uniqueFilePathSuffix != null) {
return _uniqueFilePathSuffix;
}
// Only need a few digits, so save space by modulo'ing by a prime.
// The chosen prime is the highest of six digits.
long ticks = DateTime.Now.Ticks % 999983;
_uniqueFilePathSuffix = String.Concat(UniqueFilePathSuffixID + "=", ticks.ToString("D6", CultureInfo.InvariantCulture));
_uniqueFilePathSuffix = _uniqueFilePathSuffix.PadLeft(6, '0');
return _uniqueFilePathSuffix;
}
}
// This property should be public. (DevDiv Bugs 161340)
public Control AutoPostBackControl {
get {
return _autoPostBackControl;
}
set {
_autoPostBackControl = value;
}
}
internal bool ClientSupportsFocus {
get {
return (_request != null) &&
((_request.Browser.EcmaScriptVersion >= FocusMinimumEcmaVersion) || (_request.Browser.JScriptVersion >= FocusMinimumJScriptVersion));
}
}
internal bool ClientSupportsJavaScript {
get {
if (!_clientSupportsJavaScriptChecked) {
_clientSupportsJavaScript = (_request != null) &&
(_request.Browser.EcmaScriptVersion >= JavascriptMinimumVersion);
_clientSupportsJavaScriptChecked = true;
}
return _clientSupportsJavaScript;
}
}
private ArrayList EnabledControls {
get {
if (_enabledControls == null) {
_enabledControls = new ArrayList();
}
return _enabledControls;
}
}
internal string FocusedControlID {
get {
if (_focusedControlID == null) {
return String.Empty;
}
return _focusedControlID;
}
}
/// <devdoc>
/// The control that has been set to be focused (empty if there was no such control)
/// </devdoc>
internal Control FocusedControl {
get {
return _focusedControl;
}
}
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public HtmlHead Header {
get {
return _header;
}
}
/// <internalonly/>
/// <devdoc>
/// VSWhidbey 80467: Need to adapt Id separator.
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
EditorBrowsable(EditorBrowsableState.Never)
]
public new virtual char IdSeparator {
get {
if (!_haveIdSeparator) {
if (AdapterInternal != null) {
_idSeparator = PageAdapter.IdSeparator;
}
else {
_idSeparator = IdSeparatorFromConfig;
}
_haveIdSeparator = true;
}
return _idSeparator;
}
}
/// <devdoc>
/// The control that has was last focused (empty if there was no such control)
/// </devdoc>
// We
internal string LastFocusedControl {
[AspNetHostingPermission(SecurityAction.Assert, Level = AspNetHostingPermissionLevel.Low)]
get {
if (RequestInternal != null) {
// SECURITY: Change this to just check form + query string
string lastFocus = Request[lastFocusID];
if (lastFocus != null) {
return lastFocus;
}
}
return String.Empty;
}
}
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public bool MaintainScrollPositionOnPostBack {
get {
if (RequestInternal != null && RequestInternal.Browser != null && !RequestInternal.Browser.SupportsMaintainScrollPositionOnPostback)
return false;
return _maintainScrollPosition;
}
set {
if (_maintainScrollPosition != value) {
_maintainScrollPosition = value;
if (_maintainScrollPosition) LoadScrollPosition();
}
}
}
/// <devdoc>
/// <para>The MasterPage used by the Page.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
WebSysDescription(SR.MasterPage_MasterPage)
]
public MasterPage Master {
get {
if (_master == null && !_preInitWorkComplete) {
_master = MasterPage.CreateMaster(this, Context, _masterPageFile, _contentTemplateCollection);
}
return _master;
}
}
/// <devdoc>
/// <para>Gets and sets the masterPageFile of this Page.</para>
/// </devdoc>
[
DefaultValue(""),
WebCategory("Behavior"),
WebSysDescription(SR.MasterPage_MasterPageFile)
]
public virtual string MasterPageFile {
get {
return VirtualPath.GetVirtualPathString(_masterPageFile);
}
set {
if (_preInitWorkComplete) {
throw new InvalidOperationException(SR.GetString(SR.PropertySetBeforePageEvent, "MasterPageFile", "Page_PreInit"));
}
if (value != VirtualPath.GetVirtualPathString(_masterPageFile)) {
_masterPageFile = VirtualPath.CreateAllowNull(value);
if (_master != null && Controls.Contains(_master)) {
Controls.Remove(_master);
}
_master = null;
}
}
}
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
EditorBrowsable(EditorBrowsableState.Never)
]
public int MaxPageStateFieldLength {
get {
return _maxPageStateFieldLength;
}
set {
if (this.ControlState > ControlState.FrameworkInitialized) {
throw new InvalidOperationException(SR.GetString(SR.PropertySetAfterFrameworkInitialize, "MaxPageStateFieldLength"));
}
if (value == 0 || value < -1) {
throw new ArgumentException(SR.GetString(SR.Page_Illegal_MaxPageStateFieldLength), "MaxPageStateFieldLength");
}
_maxPageStateFieldLength = value;
}
}
/// <devdoc>
/// Indicates whether page requires cross post script
/// </devdoc>
internal bool ContainsCrossPagePost {
get {
return _containsCrossPagePost;
}
set {
_containsCrossPagePost = value;
}
}
/// <devdoc>
/// True if the form should render a reference to the focus script.
/// </devdoc>
internal bool RenderFocusScript {
get {
return _requireFocusScript;
}
}
internal Stack PartialCachingControlStack {
get {
return _partialCachingControlStack;
}
}
/// <devdoc>
/// Returns the page state persister associated with the page.
/// </devdoc>
protected virtual PageStatePersister PageStatePersister {
get {
if (_persister == null) {
PageAdapter adapter = PageAdapter;
if (adapter != null) {
_persister = adapter.GetStatePersister();
}
if (_persister == null) {
_persister = new HiddenFieldPageStatePersister(this);
}
}
return _persister;
}
}
// Reconstructs the view state string from the view state fields in the request
internal string RequestViewStateString {
get {
if (!_cachedRequestViewState) {
StringBuilder state = new StringBuilder();
try {
NameValueCollection requestValueCollection = RequestValueCollection;
if (requestValueCollection != null) {
// If ViewStateChunking is disabled(-1) or there is no ViewStateFieldCount, return the __VIEWSTATE field
string fieldCountStr = RequestValueCollection[ViewStateFieldCountID];
if (MaxPageStateFieldLength == -1 || fieldCountStr == null) {
_cachedRequestViewState = true;
_requestViewState = RequestValueCollection[ViewStateFieldPrefixID];
return _requestViewState;
}
// Build up the entire persisted state from all the viewstate fields
int numViewStateFields = Convert.ToInt32(fieldCountStr, CultureInfo.InvariantCulture);
if (numViewStateFields < 0) {
throw new HttpException(SR.GetString(SR.ViewState_InvalidViewState));
}
// The view state is split into __VIEWSTATE, __VIEWSTATE1, __VIEWSTATE2, ... fields
for (int i=0; i<numViewStateFields; ++i) {
string key = ViewStateFieldPrefixID;
// For backwards compat we always need the first chunk to be __VIEWSTATE
if (i > 0) key += i.ToString(CultureInfo.InvariantCulture);
string viewStateChunk = RequestValueCollection[key];
if (viewStateChunk == null) {
throw new HttpException(SR.GetString(SR.ViewState_MissingViewStateField, key));
}
state.Append(viewStateChunk);
}
}
_cachedRequestViewState = true;
_requestViewState = state.ToString();
} catch (Exception e) {
ViewStateException.ThrowViewStateError(e, state.ToString());
}
}
return _requestViewState;
}
}
internal string ValidatorInvalidControl {
get {
if (_validatorInvalidControl == null) {
return String.Empty;
}
return _validatorInvalidControl;
}
}
/// <devdoc>
/// <para>Gets the <see cref='System.Web.TraceContext'/> object for the current Web
/// request. Tracing tracks and presents the execution details about a Web request. </para>
/// For trace data to be visible in a rendered page, you must
/// turn tracing on for that page.
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public TraceContext Trace {
get {
return Context.Trace;
}
}
/// <devdoc>
/// <para>Gets the <see langword='Request'/> object provided by the HTTP Runtime, which
/// allows you to access data from incoming HTTP requests.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public HttpRequest Request {
get {
if (_request == null)
throw new HttpException(SR.GetString(SR.Request_not_available));
return _request;
}
}
internal HttpRequest RequestInternal {
get {
return _request;
}
}
/// <devdoc>
/// <para>Gets the <see langword='Response '/>object provided by the HTTP Runtime, which
/// allows you to send HTTP response data to a client browser.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public HttpResponse Response {
get {
if (_response == null)
throw new HttpException(SR.GetString(SR.Response_not_available));
return _response;
}
}
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public RouteData RouteData {
get {
if (Context != null && Context.Request != null) {
// RequestContext is created on demand if not set so it should never be null
return Context.Request.RequestContext.RouteData;
}
return null;
}
}
/// <devdoc>
/// <para>Gets the <see langword='Server'/> object supplied by the HTTP runtime.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public HttpServerUtility Server {
get { return Context.Server;}
}
/// <devdoc>
/// <para>Retrieves a <see langword='Cache'/> object in which to store the page for
/// subsequent requests. This property is read-only.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public Cache Cache {
get {
if (_cache == null)
throw new HttpException(SR.GetString(SR.Cache_not_available));
return _cache;
}
}
/// <devdoc>
/// <para>Gets the <see langword='Session'/>
/// object provided by the HTTP Runtime. This object provides information about the current request's session.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public virtual HttpSessionState Session {
get {
if (!_sessionRetrieved) {
/* try just once to retrieve it */
_sessionRetrieved = true;
try {
_session = Context.Session;
}
catch {
// Just ignore exceptions, return null.
}
}
if (_session == null) {
throw new HttpException(SR.GetString(SR.Session_not_enabled));
}
return _session;
}
}
[
Bindable(true),
Localizable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public string Title {
get {
if ((Page.Header == null) && (this.ControlState >= ControlState.ChildrenInitialized)) {
throw new InvalidOperationException(SR.GetString(SR.Page_Title_Requires_Head));
}
if (_titleToBeSet != null) {
return _titleToBeSet;
}
return Page.Header.Title;
}
set {
if (Page.Header == null) {
if (this.ControlState >= ControlState.ChildrenInitialized) {
throw new InvalidOperationException(SR.GetString(SR.Page_Title_Requires_Head));
}
else {
_titleToBeSet = value;
}
}
else {
Page.Header.Title = value;
}
}
}
[
Bindable(true),
Localizable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public string MetaDescription {
get {
if ((Page.Header == null) && (this.ControlState >= ControlState.ChildrenInitialized)) {
throw new InvalidOperationException(SR.GetString(SR.Page_Description_Requires_Head));
}
if (_descriptionToBeSet != null) {
return _descriptionToBeSet;
}
return Page.Header.Description;
}
set {
if (Page.Header == null) {
if (this.ControlState >= ControlState.ChildrenInitialized) {
throw new InvalidOperationException(SR.GetString(SR.Page_Description_Requires_Head));
}
else {
_descriptionToBeSet = value;
}
}
else {
Page.Header.Description = value;
}
}
}
[
Bindable(true),
Localizable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public string MetaKeywords {
get {
if ((Page.Header == null) && (this.ControlState >= ControlState.ChildrenInitialized)) {
throw new InvalidOperationException(SR.GetString(SR.Page_Keywords_Requires_Head));
}
if (_keywordsToBeSet != null) {
return _keywordsToBeSet;
}
return Page.Header.Keywords;
}
set {
if (Page.Header == null) {
if (this.ControlState >= ControlState.ChildrenInitialized) {
throw new InvalidOperationException(SR.GetString(SR.Page_Keywords_Requires_Head));
}
else {
_keywordsToBeSet = value;
}
}
else {
Page.Header.Keywords = value;
}
}
}
/// <devdoc>
/// indicates whether the Page has PageTheme defined.
/// </devdoc>
internal bool ContainsTheme {
get {
Debug.Assert(_preInitWorkComplete || DesignMode, "ContainsTheme should not be accessed before Page's PreInit.");
return _theme != null;
}
}
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public virtual String Theme {
get {
return _themeName;
}
set {
if (_preInitWorkComplete) {
throw new InvalidOperationException(SR.GetString(SR.PropertySetBeforePageEvent, "Theme", "Page_PreInit"));
}
if (!String.IsNullOrEmpty(value) && !FileUtil.IsValidDirectoryName(value)) {
throw new ArgumentException(SR.GetString(SR.Page_theme_invalid_name, value), "Theme");
}
_themeName = value;
}
}
internal bool SupportsStyleSheets {
get {
if (_supportsStyleSheets == -1) {
if (Header != null &&
Header.StyleSheet != null &&
RequestInternal != null &&
Request.Browser != null &&
(string)Request.Browser["preferredRenderingType"] != "xhtml-mp" &&
Request.Browser.SupportsCss &&
!Page.IsCallback &&
(ScriptManager == null || !ScriptManager.IsInAsyncPostBack)) {
// We don't want to render the style sheet for XHTML mobile profile devices even though
// SupportsCss may be true because they need the CSS to be in a separate file.
// We don't want embedded styles sheet to render during a callback (VSWhidbey 420743)
_supportsStyleSheets = 1;
return true;
}
_supportsStyleSheets = 0;
return false;
}
return (_supportsStyleSheets == 1);
}
}
[
Browsable(false),
Filterable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public virtual String StyleSheetTheme {
get {
return _styleSheetName;
}
set {
if (_pageFlags[styleSheetInitialized]) {
throw new InvalidOperationException(SR.GetString(SR.SetStyleSheetThemeCannotBeSet));
}
_styleSheetName = value;
}
}
/// <devdoc>
/// <para>Indicates the user making the page request. This property uses the
/// Context.User property to determine where the request originates. This property
/// is read-only.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public IPrincipal User {
get { return Context.User;}
}
internal XhtmlConformanceMode XhtmlConformanceMode {
get {
// We only want the evaluation of conformance mode to be done at most once per page request.
if (!_xhtmlConformanceModeSet) {
// The conformance mode is used to determine if backward compatible markup should
// be generated as in pre-Whidbey versions. So if an adapter is assigned, we can
// assume this is Whidbey rendering and we return the default mode that doesn't do
// backward compatible rendering.
if (DesignMode) {
_xhtmlConformanceMode = XhtmlConformanceSection.DefaultMode;
}
else {
_xhtmlConformanceMode = GetXhtmlConformanceSection().Mode;
}
_xhtmlConformanceModeSet = true;
}
return _xhtmlConformanceMode;
}
}
/*
* This protected virtual method is called by the Page to create the HtmlTextWriter
* to use for rendering. The class created is based on the TagWriter property on
* the browser capabilities.
*/
/// <devdoc>
/// <para>Creates an <see cref='System.Web.UI.HtmlTextWriter'/> object to render the page's
/// content. If the <see langword='IsUplevel'/> property is set to
/// <see langword='false'/>, an <see langword='Html32TextWriter'/> object is created
/// to render requests originating from downlevel browsers. For derived pages, you
/// can override this method to create a custom text writer.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected internal virtual HtmlTextWriter CreateHtmlTextWriter(TextWriter tw) {
// Use Context.Request (rather than Request) to avoid exception in get_Request when
// Request is not available.
if (Context != null && Context.Request != null && Context.Request.Browser != null) {
return Context.Request.Browser.CreateHtmlTextWriter(tw);
}
HtmlTextWriter writer = CreateHtmlTextWriterInternal(tw, _request );
if (writer == null) {
writer = new HtmlTextWriter(tw);
}
return writer;
}
internal static HtmlTextWriter CreateHtmlTextWriterInternal(TextWriter tw, HttpRequest request) {
if (request != null && request.Browser != null) {
return request.Browser.CreateHtmlTextWriterInternal(tw);
}
// Fall back to Html 3.2
return new Html32TextWriter(tw);
}
public static HtmlTextWriter CreateHtmlTextWriterFromType(TextWriter tw, Type writerType) {
if (writerType == typeof(HtmlTextWriter)) {
return new HtmlTextWriter(tw);
}
else if (writerType == typeof(Html32TextWriter)) {
return new Html32TextWriter(tw);
}
else {
try {
// Make sure the type has the correct base class (ASURT 123677)
Util.CheckAssignableType(typeof(HtmlTextWriter), writerType);
return (HtmlTextWriter)HttpRuntime.CreateNonPublicInstance(writerType, new object[] { tw });
}
catch {
throw new HttpException(SR.GetString(SR.Invalid_HtmlTextWriter, writerType.FullName));
}
}
}
/// <devdoc>
/// Overridden to check the Page's own ID against the one being searched.
/// </devdoc>
public override Control FindControl(String id) {
if (StringUtil.EqualsIgnoreCase(id, PageID)) {
return this;
}
return base.FindControl(id, 0);
}
/*
* This method is implemented by the Page classes that we generate on
* the fly. It returns a has code unique to the control layout.
*/
/// <devdoc>
/// <para>Retrieves a hash code that is generated by <see langword='Page'/> objects that
/// are generated at runtime. This hash code is unique to the page's control
/// layout.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Never)]
public virtual int GetTypeHashCode() {
return 0;
}
/*
* Override for small efficiency win: page doesn't prepend its name
*/
internal override string GetUniqueIDPrefix() {
// Only overridde if we're at the top level
if (Parent == null)
return String.Empty;
// Use base implementation for interior nodes
return base.GetUniqueIDPrefix();
}
// This is a non-cryptographic hash code that can be used to identify which Page generated
// a __VIEWSTATE field. It shouldn't be considered sensitive information since its inputs
// are assumed to be known by all parties.
internal uint GetClientStateIdentifier() {
// Use non-randomized hash code algorithms instead of String.GetHashCode.
// Use the page's directory and class name as part of the key (ASURT 64044)
// We need to make sure that the hash is case insensitive, since the file system
// is, and strange view state errors could otherwise happen (ASURT 128657)
int pageHashCode = StringUtil.GetNonRandomizedHashCode(TemplateSourceDirectory, ignoreCase:true);
pageHashCode += StringUtil.GetNonRandomizedHashCode(GetType().Name, ignoreCase:true);
return (uint)pageHashCode;
}
/*
* Called when an exception occurs in ProcessRequest
*/
/// <devdoc>
/// <para>Throws an <see cref='System.Web.HttpException'/> object when an error occurs during a call to the
/// <see cref='System.Web.UI.Page.ProcessRequest'/> method. If there is a custom error page, and
/// custom error page handling is enabled, the method redirects to the specified
/// custom error page.</para>
/// </devdoc>
private bool HandleError(Exception e) {
try {
// Remember the exception to be accessed via Server.GetLastError/ClearError
Context.TempError = e;
// Raise the error event
OnError(EventArgs.Empty);
// If the error has been cleared by the event handler, nothing else to do
if (Context.TempError == null)
return true;
} finally {
Context.TempError = null;
}
// If an error page was specified, redirect to it
if (!String.IsNullOrEmpty(_errorPage)) {
// only redirect if custom errors are enabled:
if (Context.IsCustomErrorEnabled) {
_response.RedirectToErrorPage(_errorPage, CustomErrorsSection.GetSettings(Context).RedirectMode);
return true;
}
}
// Increment all of the appropriate error counters
PerfCounters.IncrementCounter(AppPerfCounter.ERRORS_UNHANDLED);
string traceString = null;
if (Context.TraceIsEnabled) {
Trace.Warn(SR.GetString(SR.Unhandled_Err_Error), null, e);
if (Trace.PageOutput) {
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
// Try to build the profile tree so the control hierarchy will show up
BuildPageProfileTree(false);
// these three calls will happen again at the end of the request, but
// in order to have the full trace log on the rendered page, we need
// to call them now.
Trace.EndRequest();
Trace.StopTracing();
Trace.StatusCode = 500;
Trace.Render(htw);
traceString = sw.ToString();
}
}
// If the exception is an HttpException with a formatter, just
// rethrow it instead of a new one (ASURT 45479)
if (HttpException.GetErrorFormatter(e) != null) {
return false;
}
// Don't touch security exceptions (ASURT 78366)
if (e is System.Security.SecurityException)
return false;
throw new HttpUnhandledException(null, traceString, e);
}
/// <devdoc>
/// <para>Gets a value indicating whether the page is being created in response to a
/// cross page postback.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public bool IsCrossPagePostBack {
get {
return _isCrossPagePostBack;
}
}
internal bool IsExportingWebPart {
get {
return _pageFlags[isExportingWebPart];
}
}
internal bool IsExportingWebPartShared {
get {
return _pageFlags[isExportingWebPartShared];
}
}
/*
* Returns true if this is a postback, which means it has some
* previous viewstate to reload. Use this in the Load method to differentiate
* an initial load from a postback reload.
*/
/// <devdoc>
/// <para>Gets a value indicating whether the page is being loaded in response to a
/// client postback, or if it is being loaded and accessed for the first time.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public bool IsPostBack {
get {
if (_requestValueCollection == null)
return false;
// Treat it as postback if the page is created thru cross page postback.
if (_isCrossPagePostBack)
return true;
// Don't treat it as a postback if the page is posted from cross page
if (_pageFlags[isCrossPagePostRequest])
return false;
// Don't treat it as a postback if a view state MAC check failed and we
// simply ate the exception.
if (ViewStateMacValidationErrorWasSuppressed)
return false;
// If we're in a Transfer/Execute, never treat as postback (ASURT 121000)
// Unless we are being transfered back to the original page, in which case
// it is ok to treat it as a postback (VSWhidbey 117747)
// Note that Context.Handler could be null (VSWhidbey 159775)
if (Context.ServerExecuteDepth > 0 &&
(Context.Handler == null || GetType() != Context.Handler.GetType())) {
return false;
}
// If the page control layout has changed, pretend that we are in
// a non-postback situation.
return !_fPageLayoutChanged;
}
}
internal NameValueCollection RequestValueCollection {
get { return _requestValueCollection; }
}
[
Browsable(false),
DefaultValue(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
EditorBrowsable(EditorBrowsableState.Never),
]
public virtual bool EnableEventValidation {
get {
return _enableEventValidation;
}
set {
if (this.ControlState > ControlState.FrameworkInitialized) {
throw new InvalidOperationException(SR.GetString(SR.PropertySetAfterFrameworkInitialize, "EnableEventValidation"));
}
_enableEventValidation = value;
}
}
[
Browsable(false)
]
public override bool EnableViewState {
get {
return base.EnableViewState;
}
set {
base.EnableViewState = value;
}
}
[
Browsable(false),
DefaultValue(ViewStateEncryptionMode.Auto),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
EditorBrowsable(EditorBrowsableState.Never),
]
public ViewStateEncryptionMode ViewStateEncryptionMode {
get {
return _encryptionMode;
}
set {
if (this.ControlState > ControlState.FrameworkInitialized) {
throw new InvalidOperationException(SR.GetString(SR.PropertySetAfterFrameworkInitialize, "ViewStateEncryptionMode"));
}
if (value < ViewStateEncryptionMode.Auto || value > ViewStateEncryptionMode.Never) {
throw new ArgumentOutOfRangeException("value");
}
_encryptionMode = value;
}
}
/// <devdoc>
/// <para>Setting this property helps prevent one-click attacks (ASURT 126375)</para>
/// </devdoc>
[
Browsable(false)
]
public string ViewStateUserKey {
get {
return _viewStateUserKey;
}
set {
// Make sure it's not called too late
if (ControlState >= ControlState.Initialized) {
throw new HttpException(SR.GetString(SR.Too_late_for_ViewStateUserKey));
}
_viewStateUserKey = value;
}
}
[
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never)
]
public override string ID {
get {
return base.ID;
}
set {
base.ID = value;
}
}
[
Browsable(false),
EditorBrowsable(EditorBrowsableState.Never),
DefaultValue(ValidateRequestMode.Enabled)
]
public override ValidateRequestMode ValidateRequestMode {
get {
return base.ValidateRequestMode;
}
set {
base.ValidateRequestMode = value;
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[DefaultValue(false)]
// If this property is false, then
// - we eagerly validate RawUrl at the appropriate point in ProcessRequestMain / ProcessRequestTransacted, and
// - the ClientQueryString property is populated from Request.QueryString (and might be validated) instead of Request.Unvalidated.QueryString.
public bool SkipFormActionValidation {
get {
return _pageFlags[skipFormActionValidation];
}
set {
// Clear the cached ClientQueryString value if the value of this property changes
if (value != SkipFormActionValidation) {
_clientQueryString = null;
}
_pageFlags[skipFormActionValidation] = value;
}
}
[
Browsable(false)
]
public override bool Visible {
get {
return base.Visible;
}
set {
base.Visible = value;
}
}
/// <devdoc>
/// <para>Decrypt the string using symmetric algorithm defined in config.</para>
/// </devdoc>
internal static string DecryptString(string s, Purpose purpose) {
if (s == null)
return null;
byte[] protectedData = HttpServerUtility.UrlTokenDecode(s);
// DevDiv Bugs 137864: IVType.Hash is necessary for WebResource / ScriptResource URLs
// so that client and server caching will continue to work. MS AJAX also caches these
// client-side, and switching to a different IV type could potentially break MS AJAX
// due to loading the same Javascript resource multiple times.
// MSRC 10405: Crypto board approves of this usage of IVType.Hash.
byte[] clearData = null;
if (protectedData != null) {
if (AspNetCryptoServiceProvider.Instance.IsDefaultProvider) {
// ASP.NET 4.5 Crypto DCR: Go through the new AspNetCryptoServiceProvider
// if we're configured to do so.
ICryptoService cryptoService = AspNetCryptoServiceProvider.Instance.GetCryptoService(purpose, CryptoServiceOptions.CacheableOutput);
clearData = cryptoService.Unprotect(protectedData);
}
else {
// If we're not configured to go through the new crypto routines,
// fall back to the standard MachineKey crypto routines.
#pragma warning disable 618 // calling obsolete methods
clearData = MachineKeySection.EncryptOrDecryptData(fEncrypt: false, buf: protectedData, modifier: null, start: 0, length: protectedData.Length, useValidationSymAlgo: false, useLegacyMode: false, ivType: IVType.Hash);
#pragma warning restore 618 // calling obsolete methods
}
}
if (clearData == null)
throw new HttpException(SR.GetString(SR.ViewState_InvalidViewState));
return Encoding.UTF8.GetString(clearData);
}
/*
* Performs intialization of the page required by the designer.
*/
/// <devdoc>
/// <para>Performs any initialization of the page that is required by RAD designers.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Never)]
public void DesignerInitialize() {
InitRecursive(null);
}
internal NameValueCollection GetCollectionBasedOnMethod(bool dontReturnNull) {
// Get the right NameValueCollection base on the method
if (_request.HttpVerb == HttpVerb.POST) {
return (dontReturnNull || _request.HasForm) ? _request.Form : null;
}
else {
return (dontReturnNull || _request.HasQueryString) ? _request.QueryString : null;
}
}
private bool DetermineIsExportingWebPart() {
byte[] queryString = Request.QueryStringBytes;
if ((queryString == null) || (queryString.Length < 28)) {
return false;
}
// query string is never unicode - it can be UTF-8, in which case it's fine to compare character by character
// because what we're looking for is only in the low-ASCII range.
if ((queryString[0] != '_') ||
(queryString[1] != '_') ||
(queryString[2] != 'W') ||
(queryString[3] != 'E') ||
(queryString[4] != 'B') ||
(queryString[5] != 'P') ||
(queryString[6] != 'A') ||
(queryString[7] != 'R') ||
(queryString[8] != 'T') ||
(queryString[9] != 'E') ||
(queryString[10] != 'X') ||
(queryString[11] != 'P') ||
(queryString[12] != 'O') ||
(queryString[13] != 'R') ||
(queryString[14] != 'T') ||
(queryString[15] != '=') ||
(queryString[16] != 't') ||
(queryString[17] != 'r') ||
(queryString[18] != 'u') ||
(queryString[19] != 'e') ||
(queryString[20] != '&')) {
return false;
}
// Setting the export flag so that personalization can know not to toggle modes,
// which would create a new subrequest and kill the export.
_pageFlags.Set(isExportingWebPart);
return true;
}
/*
* Determine which of the following three cases we're in:
* - Initial request. No postback, return null
* - GET postback request. Return Context.Request.QueryString
* - POST postback request. Return Context.Request.Form
*/
/// <devdoc>
/// <para>Determines the type of request made for the page based on if the page was a
/// postback, and whether a GET or POST method was used for the request.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected internal virtual NameValueCollection DeterminePostBackMode() {
if (Context.Request == null)
return null;
// If PreventPostback is set, don't treat as postback (VSWhidbey 181013).
if (Context.PreventPostback)
return null;
NameValueCollection ret = GetCollectionBasedOnMethod(dontReturnNull: false);
if (ret == null)
return null;
// Some devices may send incorrect POST strings without trailing equal signs
// if the last field is empty. Detecting this:
bool isPostback = false;
String [] nullValues = ret.GetValues(null);
if (nullValues != null) {
int numNull = nullValues.Length;
for (int i = 0; i < numNull; i++) {
if (nullValues[i].StartsWith(ViewStateFieldPrefixID, StringComparison.Ordinal) || nullValues[i] == postEventSourceID) {
isPostback = true;
break;
}
}
}
// If there is no state or postEventSourceID in the request,
// it's an initial request
//
if (ret[ViewStateFieldPrefixID] == null &&
ret[ViewStateFieldCountID] == null &&
ret[postEventSourceID] == null &&
!isPostback)
ret = null;
// If page was posted due to a HttpResponse.Redirect, ignore the postback.
else if (Request.QueryStringText.IndexOf(HttpResponse.RedirectQueryStringAssignment, StringComparison.Ordinal) != -1)
ret = null;
return ret;
}
/// <summary>
/// Returns an unvalidated name/value collection of the postback variables. This method will
/// only be called if DeterminePostBackMode() returns a non-null value.
/// This method exists to support the granular request validation feature added in .NET 4.5
/// </summary>
/// <returns>An unvalidated name/value collection of the postback variables.</returns>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected internal virtual NameValueCollection DeterminePostBackModeUnvalidated() {
// Get the right NameValueCollection base on the method. This is modeled on GetCollectionBasedOnMethod()
return _request.HttpVerb == HttpVerb.POST ? _request.Unvalidated.Form : _request.Unvalidated.QueryString;
}
/// <devdoc>
/// <para>This method is used to encrypt previous page hidden form variable that is sent to the client
/// during cross page post. This is to prevent spoofed previous pages from being instantiated and executed.</para>
/// This is also used by the AssemblyResourceLoader to prevent tampering of URLs.
/// </devdoc>
internal static string EncryptString(string s, Purpose purpose) {
Debug.Assert(s != null);
// DevDiv Bugs 137864: IVType.Hash is necessary for WebResource / ScriptResource URLs
// so that client and server caching will continue to work. MS AJAX also caches these
// client-side, and switching to a different IV type could potentially break MS AJAX
// due to loading the same Javascript resource multiple times.
// MSRC 10405: Crypto board approves of this usage of IVType.Hash.
byte[] clearData = Encoding.UTF8.GetBytes(s);
byte[] protectedData;
if (AspNetCryptoServiceProvider.Instance.IsDefaultProvider) {
// ASP.NET 4.5 Crypto DCR: Go through the new AspNetCryptoServiceProvider
// if we're configured to do so.
ICryptoService cryptoService = AspNetCryptoServiceProvider.Instance.GetCryptoService(purpose, CryptoServiceOptions.CacheableOutput);
protectedData = cryptoService.Protect(clearData);
}
else {
// If we're not configured to go through the new crypto routines,
// fall back to the standard MachineKey crypto routines.
#pragma warning disable 618 // calling obsolete methods
protectedData = MachineKeySection.EncryptOrDecryptData(fEncrypt: true, buf: clearData, modifier: null, start: 0, length: clearData.Length, useValidationSymAlgo: false, useLegacyMode: false, ivType: IVType.Hash);
#pragma warning restore 618 // calling obsolete methods
}
return HttpServerUtility.UrlTokenEncode(protectedData);
}
private void LoadAllState() {
object state = LoadPageStateFromPersistenceMedium();
IDictionary controlStates = null;
Pair allSavedViewState = null;
Pair statePair = state as Pair;
if (state != null) {
controlStates = statePair.First as IDictionary;
allSavedViewState = statePair.Second as Pair;
}
// The control state (controlStatePair) was saved as an dictionary of objects:
// 1. A list of controls that require postback[under the page id]
// 2. A dictionary of control states
if (controlStates != null) {
_controlsRequiringPostBack = (ArrayList)controlStates[PageRegisteredControlsThatRequirePostBackKey];
if (_registeredControlsRequiringControlState != null) {
foreach (Control ctl in _registeredControlsRequiringControlState) {
ctl.LoadControlStateInternal(controlStates[ctl.UniqueID]);
}
}
}
// The view state (allSavedViewState) was saved as an array of objects:
// 1. The hash code string
// 2. The state of the entire control hierarchy
// Is there any state?
if (allSavedViewState != null) {
// Get the hash code from the state
string hashCode = (string) allSavedViewState.First;
// If it's different from the current one, the layout has changed
int viewhash = Int32.Parse(hashCode, NumberFormatInfo.InvariantInfo);
_fPageLayoutChanged = viewhash != GetTypeHashCode();
// If the page control layout has changed, don't attempt to
// load any more state.
if (!_fPageLayoutChanged) {
// UNCOMMENT FOR DEBUG OUTPUT
// WalkViewState(allSavedViewState.Second, null, 0);
LoadViewStateRecursive(allSavedViewState.Second);
}
}
}
/*
* Override this method to persist view state to something other
* than hidden fields (
*/
/// <devdoc>
/// <para>Loads any saved view state information to the page. Override this method if
/// you want to load the page view state in anything other than a hidden field.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected internal virtual object LoadPageStateFromPersistenceMedium() {
PageStatePersister persister = PageStatePersister;
try {
persister.Load();
}
catch (HttpException e) {
//VSWhidbey 201601. Ignore the exception in cross-page post
//since this might be a cross application postback.
if (_pageFlags[isCrossPagePostRequest]) {
return null;
}
// DevDiv #461378: Ignore validation errors for cross-page postbacks.
if (ShouldSuppressMacValidationException(e)) {
if (Context != null && Context.TraceIsEnabled) {
Trace.Write("aspx.page", "Ignoring page state", e);
}
ViewStateMacValidationErrorWasSuppressed = true;
return null;
}
e.WebEventCode = WebEventCodes.RuntimeErrorViewStateFailure;
throw;
}
return new Pair(persister.ControlState, persister.ViewState);
}
private bool ViewStateMacValidationErrorWasSuppressed {
get { return _pageFlags[wasViewStateMacErrorSuppressed]; }
set { _pageFlags[wasViewStateMacErrorSuppressed] = value; }
}
internal bool ShouldSuppressMacValidationException(Exception e) {
// If the patch isn't active, don't suppress anything, as it would be a change in behavior.
if (!EnableViewStateMacRegistryHelper.SuppressMacValidationErrorsFromCrossPagePostbacks) {
return false;
}
// We check the __VIEWSTATEGENERATOR field for an identifier that matches the current Page.
// If the generator field exists and says that the current Page generated the incoming
// __VIEWSTATE field, then a validation failure represents a real error and we need to
// surface this information to the developer for resolution. Otherwise we assume this
// view state was not meant for us, so if validation fails we'll just ignore __VIEWSTATE.
if (ViewStateException.IsMacValidationException(e)) {
if (EnableViewStateMacRegistryHelper.SuppressMacValidationErrorsAlways) {
return true;
}
// DevDiv #841854: VSUK is often used for CSRF checks, so we can't ---- MAC exceptions by default in this case.
if (!String.IsNullOrEmpty(ViewStateUserKey)) {
return false;
}
if (_requestValueCollection == null) {
return true;
}
if (!VerifyClientStateIdentifier(_requestValueCollection[ViewStateGeneratorFieldID])) {
return true;
}
}
return false;
}
private bool VerifyClientStateIdentifier(string identifier) {
// Returns true iff we can parse the incoming identifier and it matches our own.
// If we can't parse the identifier, then by definition we didn't generate it.
uint parsedIdentifier;
return identifier != null
&& UInt32.TryParse(identifier, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out parsedIdentifier)
&& parsedIdentifier == GetClientStateIdentifier();
}
internal void LoadScrollPosition() {
// Don't load scroll position if the previous page was a crosspage postback
if (_previousPagePath != null) {
return;
}
// Load the scroll positions from the request if they exist
if (_requestValueCollection != null) {
double doubleValue;
string xpos = _requestValueCollection[_scrollPositionXID];
if (xpos != null) {
_scrollPositionX = HttpUtility.TryParseCoordinates(xpos, out doubleValue) ? (int)doubleValue : 0 ;
}
string ypos = _requestValueCollection[_scrollPositionYID];
if (ypos != null) {
_scrollPositionY = HttpUtility.TryParseCoordinates(ypos, out doubleValue) ? (int)doubleValue : 0 ;
}
}
}
internal IStateFormatter2 CreateStateFormatter() {
return new ObjectStateFormatter(this, true);
}
// Decomposes the large view state string into pieces of size <= MaxPageStateFieldLength
internal ICollection DecomposeViewStateIntoChunks() {
string state = ClientState;
if (state == null) return null;
// Any value less than or equal to 0 turns off chunking
if (MaxPageStateFieldLength <= 0) {
ArrayList chunks = new ArrayList(1);
chunks.Add(state);
return chunks;
}
// Break up the view state into the correctly sized chunks
int numFullChunks = ClientState.Length / MaxPageStateFieldLength;
ArrayList viewStateChunks = new ArrayList(numFullChunks+1);
int curPos = 0;
for (int i=0; i<numFullChunks; i++) {
viewStateChunks.Add(state.Substring(curPos, MaxPageStateFieldLength));
curPos += MaxPageStateFieldLength;
}
// Add the leftover characters
if (curPos < state.Length) {
viewStateChunks.Add(state.Substring(curPos));
}
// Always want to return at least one empty chunk
if (viewStateChunks.Count == 0) {
viewStateChunks.Add(String.Empty);
}
return viewStateChunks;
}
internal void RenderViewStateFields(HtmlTextWriter writer) {
if (_hiddenFieldsToRender == null) {
_hiddenFieldsToRender = new Dictionary<string, string>();
}
if (ClientState != null) {
ICollection viewStateChunks = DecomposeViewStateIntoChunks();
writer.WriteLine();
// Don't write out a view state field count if there is only 1 viewstate field
if (viewStateChunks.Count > 1) {
string value = viewStateChunks.Count.ToString(CultureInfo.InvariantCulture);
writer.Write("<input type=\"hidden\" name=\"");
writer.Write(ViewStateFieldCountID);
writer.Write("\" id=\"");
writer.Write(ViewStateFieldCountID);
writer.Write("\" value=\"");
writer.Write(value);
writer.WriteLine("\" />");
_hiddenFieldsToRender[ViewStateFieldCountID] = value;
}
int count = 0;
foreach (string stateChunk in viewStateChunks) {
writer.Write("<input type=\"hidden\" name=\"");
string name = ViewStateFieldPrefixID;
writer.Write(ViewStateFieldPrefixID);
string countString = null;
if (count > 0) {
countString = count.ToString(CultureInfo.InvariantCulture);
name += countString;
writer.Write(countString);
}
writer.Write("\" id=\"");
writer.Write(name);
writer.Write("\" value=\"");
writer.Write(stateChunk);
writer.WriteLine("\" />");
++count;
_hiddenFieldsToRender[name] = stateChunk;
}
// DevDiv #461378: Write out an identifier so we know who generated this __VIEWSTATE field.
// It doesn't need to be MACed since the only thing we use it for is error suppression,
// similar to how __PREVIOUSPAGE works.
if (EnableViewStateMacRegistryHelper.WriteViewStateGeneratorField) {
// hex is easier than base64 to work with and consumes only one extra byte on the wire
ClientScript.RegisterHiddenField(ViewStateGeneratorFieldID, GetClientStateIdentifier().ToString("X8", CultureInfo.InvariantCulture));
}
}
else {
// ASURT 106992
// Need to always render out the viewstate field so alternate viewstate persistence will get called
writer.Write("\r\n<input type=\"hidden\" name=\"");
writer.Write(ViewStateFieldPrefixID);
// Dev10 Bug 486494
// Remove previously rendered NewLine
writer.Write("\" id=\"");
writer.Write(ViewStateFieldPrefixID);
writer.WriteLine("\" value=\"\" />");
_hiddenFieldsToRender[ViewStateFieldPrefixID] = String.Empty;
}
}
/// <devdoc>
/// Default markup for begin form.
/// </devdoc>
internal void BeginFormRender(HtmlTextWriter writer, string formUniqueID) {
// DevDiv 27324: Form should render div tag around hidden inputs
// DevDiv 33149: backward compat. switch for obsolete rendering
// Dev10 705089: in 4.0 mode or later, we render the div block with class="aspNetHidden" for xHTML conformance.
bool renderDivAroundHiddenInputs = RenderDivAroundHiddenInputs(writer);
if (renderDivAroundHiddenInputs) {
writer.WriteLine();
if (RenderingCompatibility >= VersionUtil.Framework40) {
writer.Write("<div class=\"" + HiddenClassName + "\">");
}
else {
writer.Write("<div>");
}
}
ClientScript.RenderHiddenFields(writer);
RenderViewStateFields(writer);
if (renderDivAroundHiddenInputs) {
writer.WriteLine("</div>");
}
if (ClientSupportsJavaScript) {
if (MaintainScrollPositionOnPostBack && _requireScrollScript == false) {
ClientScript.RegisterHiddenField(_scrollPositionXID, _scrollPositionX.ToString(CultureInfo.InvariantCulture));
ClientScript.RegisterHiddenField(_scrollPositionYID, _scrollPositionY.ToString(CultureInfo.InvariantCulture));
ClientScript.RegisterStartupScript(typeof(Page), PageScrollPositionScriptKey, @"
theForm.oldSubmit = theForm.submit;
theForm.submit = WebForm_SaveScrollPositionSubmit;
theForm.oldOnSubmit = theForm.onsubmit;
theForm.onsubmit = WebForm_SaveScrollPositionOnSubmit;
" + (IsPostBack ? @"
theForm.oldOnLoad = window.onload;
window.onload = WebForm_RestoreScrollPosition;
" : String.Empty), true);
RegisterWebFormsScript();
_requireScrollScript = true;
}
// VSWhidbey 375885, Render the focus script later (specifically for interaction with scrollposition)
if (ClientSupportsFocus && Form != null && (RenderFocusScript || (Form.DefaultFocus.Length > 0) || (Form.DefaultButton.Length > 0))) {
string focusedControlId = String.Empty;
// Someone calling SetFocus(controlId) is the most precendent
if (FocusedControlID.Length > 0) {
focusedControlId = FocusedControlID;
}
else if (FocusedControl != null) {
if (FocusedControl.Visible) {
focusedControlId = FocusedControl.ClientID;
}
}
else if (ValidatorInvalidControl.Length > 0) {
focusedControlId = ValidatorInvalidControl;
}
// AutoPostBack focus is the second least precendent
else if (LastFocusedControl.Length > 0) {
// This doesn't have to be an ASP.NET control
focusedControlId = LastFocusedControl;
}
// DefaultFocus is the next
else if (Form.DefaultFocus.Length > 0) {
// VSWhidbey 379627: Always render the default focus, regardless if we can find it, or if its visible
focusedControlId = Form.DefaultFocus;
}
// DefaultButton is the least precendent
else if (Form.DefaultButton.Length > 0) {
focusedControlId = Form.DefaultButton;
}
// If something got focused, render some script to focus it only if its safe
int match;
if (focusedControlId.Length > 0 && !CrossSiteScriptingValidation.IsDangerousString(focusedControlId, out match) &&
CrossSiteScriptingValidation.IsValidJavascriptId(focusedControlId)) {
ClientScript.RegisterClientScriptResource(typeof(HtmlForm), "Focus.js");
if (!ClientScript.IsClientScriptBlockRegistered(typeof(HtmlForm), "Focus")) {
RegisterWebFormsScript();
ClientScript.RegisterStartupScript(
typeof(HtmlForm),
"Focus",
"WebForm_AutoFocus('" + Util.QuoteJScriptString(focusedControlId) + "');",
true);
}
IScriptManager scriptManager = ScriptManager;
if (scriptManager != null) {
scriptManager.SetFocusInternal(focusedControlId);
}
}
}
// Set the necessary stuff to re-enable disabled controls on the client
if (RenderDisabledControlsScript) {
ClientScript.RegisterOnSubmitStatement(typeof(Page), PageReEnableControlsScriptKey, "WebForm_ReEnableControls();");
RegisterWebFormsScript();
}
if (_fRequirePostBackScript) {
RenderPostBackScript(writer, formUniqueID);
}
if (_fRequireWebFormsScript) {
RenderWebFormsScript(writer);
}
}
ClientScript.RenderClientScriptBlocks(writer);
}
internal void EndFormRenderArrayAndExpandoAttribute(HtmlTextWriter writer, string formUniqueID) {
if (ClientSupportsJavaScript) {
// Devdiv 9409 - Register the array for reenabling only after the controls have been processed,
// so that list controls can have their children registered.
if (RenderDisabledControlsScript) {
foreach (Control control in EnabledControls) {
ClientScript.RegisterArrayDeclaration(EnabledControlArray, "'" + control.ClientID + "'");
}
}
ClientScript.RenderArrayDeclares(writer);
ClientScript.RenderExpandoAttribute(writer);
}
}
private bool RenderDisabledControlsScript {
get {
return Form.SubmitDisabledControls && (EnabledControls.Count > 0) &&
(_request.Browser.W3CDomVersion.Major > 0);
}
}
internal void EndFormRenderHiddenFields(HtmlTextWriter writer, string formUniqueID) {
if (RequiresViewStateEncryptionInternal) {
ClientScript.RegisterHiddenField(ViewStateEncryptionID, String.Empty);
}
if (_containsCrossPagePost) {
string path = EncryptString(Request.CurrentExecutionFilePath, Purpose.WebForms_Page_PreviousPageID);
ClientScript.RegisterHiddenField(previousPageID, path);
}
if (EnableEventValidation) {
ClientScript.SaveEventValidationField();
}
if (ClientScript.HasRegisteredHiddenFields) {
bool renderDivAroundHiddenInputs = RenderDivAroundHiddenInputs(writer);
if (renderDivAroundHiddenInputs) {
writer.WriteLine();
if (RenderingCompatibility >= VersionUtil.Framework40) {
writer.AddAttribute(HtmlTextWriterAttribute.Class, HiddenClassName);
}
writer.RenderBeginTag(HtmlTextWriterTag.Div);
}
ClientScript.RenderHiddenFields(writer);
if (renderDivAroundHiddenInputs) {
writer.RenderEndTag(); // DIV
}
}
}
internal void EndFormRenderPostBackAndWebFormsScript(HtmlTextWriter writer, string formUniqueID) {
if (ClientSupportsJavaScript) {
if (_fRequirePostBackScript && !_fPostBackScriptRendered) {
RenderPostBackScript(writer, formUniqueID);
}
if (_fRequireWebFormsScript && !_fWebFormsScriptRendered)
RenderWebFormsScript(writer);
}
ClientScript.RenderClientStartupScripts(writer);
}
/// <devdoc>
/// Default markup for end form.
/// </devdoc>
internal void EndFormRender(HtmlTextWriter writer, string formUniqueID) {
EndFormRenderArrayAndExpandoAttribute(writer, formUniqueID);
EndFormRenderHiddenFields(writer, formUniqueID);
EndFormRenderPostBackAndWebFormsScript(writer, formUniqueID);
}
// VSWhidbey 475945: For ClientScriptManager.GetPostBackEventReference() to check if '$' should be used for id separator
internal bool IsInOnFormRender {
get {
return _inOnFormRender;
}
}
/// <devdoc>
/// Called by both adapters and default rendering prior to form rendering.
/// </devdoc>
internal void OnFormRender() {
// Make sure there is only one form tag (ASURT 18891, 18894)
if (_fOnFormRenderCalled) {
throw new HttpException(SR.GetString(SR.Multiple_forms_not_allowed));
}
_fOnFormRenderCalled = true;
_inOnFormRender = true;
}
/// <devdoc>
/// Called by both adapters and default rendering after form rendering.
/// </devdoc>
internal void OnFormPostRender(HtmlTextWriter writer) {
_inOnFormRender = false;
if (_postFormRenderDelegate != null) {
_postFormRenderDelegate(writer, null);
}
}
/// <devdoc>
/// Needed by adapters which do more than one pass, so that OnFormRender can be called more than once.
/// </devdoc>
//
internal void ResetOnFormRenderCalled() {
_fOnFormRenderCalled = false;
}
/// <devdoc>
/// Sets focus to the specified control
/// </devdoc>
public void SetFocus(Control control) {
if (control == null) {
throw new ArgumentNullException("control");
}
if (Form == null) {
throw new InvalidOperationException(SR.GetString(SR.Form_Required_For_Focus));
}
if (Form.ControlState == ControlState.PreRendered) {
throw new InvalidOperationException(SR.GetString(SR.Page_MustCallBeforeAndDuringPreRender, "SetFocus"));
}
_focusedControl = control;
_focusedControlID = null;
RegisterFocusScript();
}
/// <devdoc>
/// Sets focus to the specified client id
/// </devdoc>
public void SetFocus(string clientID) {
if ((clientID == null) || (clientID.Trim().Length == 0)) {
throw new ArgumentNullException("clientID");
}
if (Form == null) {
throw new InvalidOperationException(SR.GetString(SR.Form_Required_For_Focus));
}
if (Form.ControlState == ControlState.PreRendered) {
throw new InvalidOperationException(SR.GetString(SR.Page_MustCallBeforeAndDuringPreRender, "SetFocus"));
}
_focusedControlID = clientID.Trim();
_focusedControl = null;
RegisterFocusScript();
}
internal void SetValidatorInvalidControlFocus(string clientID) {
if (String.IsNullOrEmpty(_validatorInvalidControl)) {
_validatorInvalidControl = clientID;
RegisterFocusScript();
}
}
//Note: BCL should provide a way to abort threads without asserting ControlThread for platform internal code.
[SecurityPermission(SecurityAction.Assert, ControlThread = true)]
internal static void ThreadResetAbortWithAssert() {
Thread.ResetAbort();
}
/*
* Enables controls to obtain client-side script function that will cause
* (when invoked) a server post-back to the form.
*/
/// <devdoc>
/// <para>
/// Associates the reference to the control that will
/// process the postback on the server.
/// </para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Obsolete("The recommended alternative is ClientScript.GetPostBackEventReference. http://go.microsoft.com/fwlink/?linkid=14202")]
public string GetPostBackEventReference(Control control) {
return ClientScript.GetPostBackEventReference(control, String.Empty);
}
/*
* Enables controls to obtain client-side script function that will cause
* (when invoked) a server post-back to the form.
* argument: Parameter that will be passed to control on server
*/
/// <devdoc>
/// <para>Passes a parameter to the control that will do the postback processing on the
/// server.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Obsolete("The recommended alternative is ClientScript.GetPostBackEventReference. http://go.microsoft.com/fwlink/?linkid=14202")]
public string GetPostBackEventReference(Control control,
string argument) {
return ClientScript.GetPostBackEventReference(control, argument);
}
/// <devdoc>
/// <para>This returs a string that can be put in client event to post back to the named control</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Obsolete("The recommended alternative is ClientScript.GetPostBackEventReference. http://go.microsoft.com/fwlink/?linkid=14202")]
public string GetPostBackClientEvent(Control control, string argument) {
return ClientScript.GetPostBackEventReference(control, argument);
}
/// <devdoc>
/// <para>This returs a string that can be put in client event to post back to the named control</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Obsolete("The recommended alternative is ClientScript.GetPostBackClientHyperlink. http://go.microsoft.com/fwlink/?linkid=14202")]
public string GetPostBackClientHyperlink(Control control, string argument) {
return ClientScript.GetPostBackClientHyperlink(control, argument, false);
}
internal void InitializeStyleSheet() {
if (_pageFlags[styleSheetInitialized]) {
return;
}
String styleSheetName = StyleSheetTheme;
if (!String.IsNullOrEmpty(styleSheetName)) {
BuildResultCompiledType resultType = ThemeDirectoryCompiler.GetThemeBuildResultType(
Context, styleSheetName);
if (resultType != null) {
_styleSheet = (PageTheme)resultType.CreateInstance();
_styleSheet.Initialize(this, true);
}
else {
throw new HttpException(SR.GetString(SR.Page_theme_not_found, styleSheetName));
}
}
_pageFlags.Set(styleSheetInitialized);
}
private void InitializeThemes() {
String themeName = Theme;
if (!String.IsNullOrEmpty(themeName)) {
BuildResultCompiledType resultType = ThemeDirectoryCompiler.GetThemeBuildResultType(
Context, themeName);
if (resultType != null) {
_theme = (PageTheme)resultType.CreateInstance();
_theme.Initialize(this, false);
}
else {
throw new HttpException(SR.GetString(SR.Page_theme_not_found, themeName));
}
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
protected internal void AddContentTemplate(string templateName, ITemplate template) {
if (_contentTemplateCollection == null) {
_contentTemplateCollection = new Hashtable(11, StringComparer.OrdinalIgnoreCase);
}
try {
_contentTemplateCollection.Add(templateName, template);
}
catch (ArgumentException) {
throw new HttpException(SR.GetString(SR.MasterPage_Multiple_content, templateName));
}
}
private void ApplyMasterPage() {
if (Master != null) {
ArrayList appliedMasterPages = new ArrayList();
appliedMasterPages.Add(_masterPageFile.VirtualPathString.ToLower(CultureInfo.InvariantCulture));
MasterPage.ApplyMasterRecursive(Master, appliedMasterPages);
}
}
internal void ApplyControlSkin(Control ctrl) {
if (_theme != null) {
_theme.ApplyControlSkin(ctrl);
}
}
internal bool ApplyControlStyleSheet(Control ctrl) {
if (_styleSheet != null) {
_styleSheet.ApplyControlSkin(ctrl);
return true;
}
return false;
}
internal void RegisterFocusScript() {
if (ClientSupportsFocus && (_requireFocusScript == false)) {
ClientScript.RegisterHiddenField(lastFocusID, String.Empty);
_requireFocusScript = true;
// If there are any partial caching controls on the stack, forward the call to them
if (_partialCachingControlStack != null) {
foreach(BasePartialCachingControl c in _partialCachingControlStack) {
c.RegisterFocusScript();
}
}
}
}
internal void RegisterPostBackScript() {
if (!ClientSupportsJavaScript) {
return;
}
if (_fPostBackScriptRendered) {
return;
}
if (!_fRequirePostBackScript) {
ClientScript.RegisterHiddenField(postEventSourceID, String.Empty);
ClientScript.RegisterHiddenField(postEventArgumentID, String.Empty);
_fRequirePostBackScript = true;
}
// If there are any partial caching controls on the stack, forward the call to them
if (_partialCachingControlStack != null) {
foreach(BasePartialCachingControl c in _partialCachingControlStack) {
c.RegisterPostBackScript();
}
}
}
private void RenderPostBackScript(HtmlTextWriter writer, string formUniqueID) {
writer.Write(EnableLegacyRendering ?
ClientScriptManager.ClientScriptStartLegacy :
ClientScriptManager.ClientScriptStart);
if (PageAdapter != null) {
writer.Write("var theForm = ");
writer.Write(PageAdapter.GetPostBackFormReference(formUniqueID));
writer.WriteLine(";");
}
else {
writer.Write("var theForm = document.forms['");
writer.Write(formUniqueID);
writer.WriteLine("'];");
// VSWhidbey 392597: Try to use the document._ctl00 syntax since PocketPC doesn't support document.forms[id]
writer.Write("if (!theForm) {\r\n theForm = document.");
writer.Write(formUniqueID);
writer.WriteLine(";\r\n}");
}
writer.WriteLine(@"function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}");
writer.WriteLine(EnableLegacyRendering ?
ClientScriptManager.ClientScriptEndLegacy :
ClientScriptManager.ClientScriptEnd);
_fPostBackScriptRendered = true;
}
/// <devdoc>
/// Allows controls on a page to access to the _doPostBack and _doCallback JavaScript handlers on the
/// client. This method can be called multiple times by multiple controls. It should
/// render only one instance of the WebForms script.
/// </devdoc>
internal void RegisterWebFormsScript() {
if (ClientSupportsJavaScript) {
if (_fWebFormsScriptRendered) {
return;
}
RegisterPostBackScript();
_fRequireWebFormsScript = true;
// If there are any partial caching controls on the stack, forward the call to them
if (_partialCachingControlStack != null) {
foreach(BasePartialCachingControl c in _partialCachingControlStack) {
c.RegisterWebFormsScript();
}
}
}
}
private void RenderWebFormsScript(HtmlTextWriter writer) {
ClientScript.RenderWebFormsScript(writer);
_fWebFormsScriptRendered = true;
}
/// <devdoc>
/// <para>Determines if the client script block is registered with the page.</para>
/// </devdoc>
[Obsolete("The recommended alternative is ClientScript.IsClientScriptBlockRegistered(string key). http://go.microsoft.com/fwlink/?linkid=14202")]
public bool IsClientScriptBlockRegistered(string key) {
return ClientScript.IsClientScriptBlockRegistered(typeof(Page), key);
}
/// <devdoc>
/// <para>Determines if the client startup script is registered with the
/// page.</para>
/// </devdoc>
[Obsolete("The recommended alternative is ClientScript.IsStartupScriptRegistered(string key). http://go.microsoft.com/fwlink/?linkid=14202")]
public bool IsStartupScriptRegistered(string key) {
return ClientScript.IsStartupScriptRegistered(typeof(Page), key);
}
/// <devdoc>
/// <para>Declares a value that will be declared as a JavaScript array declaration
/// when the page renders. This can be used by script-based controls to declare
/// themselves within an array so that a client script library can work with
/// all the controls of the same type.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Obsolete("The recommended alternative is ClientScript.RegisterArrayDeclaration(string arrayName, string arrayValue). http://go.microsoft.com/fwlink/?linkid=14202")]
public void RegisterArrayDeclaration(string arrayName, string arrayValue) {
ClientScript.RegisterArrayDeclaration(arrayName, arrayValue);
}
/// <devdoc>
/// <para>
/// Allows controls to automatically register a hidden field on the form. The
/// field will be emitted when the form control renders itself.
/// </para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Obsolete("The recommended alternative is ClientScript.RegisterHiddenField(string hiddenFieldName, string hiddenFieldInitialValue). http://go.microsoft.com/fwlink/?linkid=14202")]
public virtual void RegisterHiddenField(string hiddenFieldName, string hiddenFieldInitialValue) {
ClientScript.RegisterHiddenField(hiddenFieldName, hiddenFieldInitialValue);
}
/// <devdoc>
/// <para> Prevents controls from sending duplicate blocks of
/// client-side script to the client. Any script blocks with the same <paramref name="key"/> parameter
/// values are considered duplicates.</para>
/// </devdoc>
[Obsolete("The recommended alternative is ClientScript.RegisterClientScriptBlock(Type type, string key, string script). http://go.microsoft.com/fwlink/?linkid=14202")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
public virtual void RegisterClientScriptBlock(string key, string script) {
ClientScript.RegisterClientScriptBlock(typeof(Page), key, script);
}
/// <devdoc>
/// <para>
/// Allows controls to keep duplicate blocks of client-side script code from
/// being sent to the client. Any script blocks with the same <paramref name="key"/> parameter
/// value are considered duplicates.
/// </para>
/// </devdoc>
[Obsolete("The recommended alternative is ClientScript.RegisterStartupScript(Type type, string key, string script). http://go.microsoft.com/fwlink/?linkid=14202")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
public virtual void RegisterStartupScript(string key, string script) {
ClientScript.RegisterStartupScript(typeof(Page), key, script, false);
}
/// <devdoc>
/// <para>Allows a control to access a the client
/// <see langword='onsubmit'/> event.
/// The script should be a function call to client code registered elsewhere.</para>
/// </devdoc>
[Obsolete("The recommended alternative is ClientScript.RegisterOnSubmitStatement(Type type, string key, string script). http://go.microsoft.com/fwlink/?linkid=14202")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
public void RegisterOnSubmitStatement(string key, string script) {
ClientScript.RegisterOnSubmitStatement(typeof(Page), key, script);
}
internal void RegisterEnabledControl(Control control) {
EnabledControls.Add(control);
}
/// <devdoc>
/// <para>If called, Control State for this control will be persisted.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public void RegisterRequiresControlState(Control control) {
if (control == null) {
throw new ArgumentException(SR.GetString(SR.Page_ControlState_ControlCannotBeNull));
}
if (control.ControlState == ControlState.PreRendered) {
throw new InvalidOperationException(SR.GetString(SR.Page_MustCallBeforeAndDuringPreRender, "RegisterRequiresControlState"));
}
if (_registeredControlsRequiringControlState == null) {
_registeredControlsRequiringControlState = new ControlSet();
}
// Don't do anything if RegisterRequiresControlState is called multiple times on the same control.
if (!_registeredControlsRequiringControlState.Contains(control)) {
_registeredControlsRequiringControlState.Add(control);
IDictionary controlState = (IDictionary)PageStatePersister.ControlState;
if (controlState != null) {
string uniqueID = control.UniqueID;
// VSWhidbey 422416: We allow control state loaded only once, to
// match the same behavior of ViewState loading in Control.AddedControl
// method which ViewState is removed after applied once. The
// scenario is having a control to be re-parented multiple times.
// Note: We can't call remove here, because we may be in the middle of iterating thru
// the keys of controlState(within in a call to RegisterRequiresClearChildControlState),
// so we just remember that we loaded this control's control state
if (!ControlStateLoadedControlIds.Contains(uniqueID)) {
control.LoadControlStateInternal(controlState[uniqueID]);
ControlStateLoadedControlIds.Add(uniqueID);
}
}
}
}
public bool RequiresControlState(Control control) {
return (_registeredControlsRequiringControlState != null && _registeredControlsRequiringControlState.Contains(control));
}
/// <devdoc>
/// <para>If called, Control State for this control will no longer persisted.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public void UnregisterRequiresControlState(Control control) {
if (control == null) {
throw new ArgumentException(SR.GetString(SR.Page_ControlState_ControlCannotBeNull));
}
if (_registeredControlsRequiringControlState == null) {
return;
}
_registeredControlsRequiringControlState.Remove(control);
}
internal bool ShouldLoadControlState(Control control) {
if (_registeredControlsRequiringClearChildControlState == null) return true;
foreach (Control cleared in _registeredControlsRequiringClearChildControlState.Keys) {
if (control != cleared && control.IsDescendentOf(cleared)) return false;
}
return true;
}
internal void RegisterRequiresClearChildControlState(Control control) {
if (_registeredControlsRequiringClearChildControlState == null) {
_registeredControlsRequiringClearChildControlState = new HybridDictionary();
_registeredControlsRequiringClearChildControlState.Add(control, true);
}
else if (_registeredControlsRequiringClearChildControlState[control] == null) {
_registeredControlsRequiringClearChildControlState.Add(control, true);
}
IDictionary controlState = (IDictionary)PageStatePersister.ControlState;
if (controlState != null) {
// Clear out the control state for children of this control
List<string> controlsToClear = new List<string>(controlState.Count);
foreach (string id in controlState.Keys) {
Control controlWithState = FindControl(id);
if (controlWithState != null && controlWithState.IsDescendentOf(control)) {
controlsToClear.Add(id);
}
}
foreach (string id in controlsToClear) {
controlState[id] = null;
}
}
}
/// <devdoc>
/// <para>Registers a control as one that requires postback handling.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public void RegisterRequiresPostBack(Control control) {
// Fail if the control is not an IPostBackDataHandler (VSWhidbey 184483)
if (!(control is IPostBackDataHandler)) {
IPostBackDataHandler dataHandler = control.AdapterInternal as IPostBackDataHandler;
if (dataHandler == null)
throw new HttpException(SR.GetString(SR.Ctrl_not_data_handler));
}
if (_registeredControlsThatRequirePostBack == null)
_registeredControlsThatRequirePostBack = new ArrayList();
_registeredControlsThatRequirePostBack.Add(control.UniqueID);
}
// Push a BasePartialCachingControl on the stack of registered caching controls
internal void PushCachingControl(BasePartialCachingControl c) {
// Create the stack on demand
if (_partialCachingControlStack == null) {
_partialCachingControlStack = new Stack();
}
_partialCachingControlStack.Push(c);
}
// Pop a BasePartialCachingControl from the stack of registered caching controls
internal void PopCachingControl() {
Debug.Assert(_partialCachingControlStack != null);
_partialCachingControlStack.Pop();
}
/*
* This method will process the data posted back in the request header.
* The collection of posted data keys consists of three types :
* 1. Fully qualified ids of controls. The associated value is the data
* posted back by the browser for an intrinsic html element.
* 2. Fully qualified ids of controls that have explicitly registered that
* they want to be notified on postback. This is required for intrinsic
* html elements that for some states do not postback data ( e.g. a select
* when there is no selection, a checkbox or radiobutton that is not checked )
* The associated value for these keys is not relevant.
* 3. Framework generated hidden fields for event processing, whose values are
* set by client-side script prior to postback.
*
* This method handles the process of notifying the relevant controls that a postback
* has occurred, via the IPostBackDataHandler interface.
*
* It can potentially be called twice: before and after LoadControl. This is to
* handle the case where users programmatically add controls in Page_Load (ASURT 29045).
*/
private void ProcessPostData(NameValueCollection postData, bool fBeforeLoad) {
if (_changedPostDataConsumers == null)
_changedPostDataConsumers = new ArrayList();
// identify controls that have postback data
if (postData != null) {
foreach (string postKey in postData) {
if (postKey != null) {
// Ignore system post fields
if (IsSystemPostField(postKey))
continue;
Control ctrl = FindControl(postKey);
if (ctrl == null) {
if (fBeforeLoad) {
// It was not found, so keep track of it for the post load attempt
if (_leftoverPostData == null)
_leftoverPostData = new NameValueCollection();
_leftoverPostData.Add(postKey, null);
}
continue;
}
IPostBackDataHandler consumer = ctrl.PostBackDataHandler;
// Ignore controls that are not IPostBackDataHandler (see ASURT 13581)
if (consumer == null) {
// If it's a IPostBackEventHandler (which doesn't implement IPostBackDataHandler),
// register it (ASURT 39040)
if(ctrl.PostBackEventHandler != null)
RegisterRequiresRaiseEvent(ctrl.PostBackEventHandler);
continue;
}
bool changed;
if(consumer != null) {
NameValueCollection postCollection = ctrl.CalculateEffectiveValidateRequest() ? _requestValueCollection : _unvalidatedRequestValueCollection;
changed = consumer.LoadPostData(postKey, postCollection);
if(changed)
_changedPostDataConsumers.Add(ctrl);
}
// ensure controls are only notified of postback once
if (_controlsRequiringPostBack != null)
_controlsRequiringPostBack.Remove(postKey);
}
}
}
// Keep track of the leftover for the post-load attempt
ArrayList leftOverControlsRequiringPostBack = null;
// process controls that explicitly registered to be notified of postback
if (_controlsRequiringPostBack != null) {
foreach (string controlID in _controlsRequiringPostBack) {
Control c = FindControl(controlID);
if (c != null) {
IPostBackDataHandler consumer = c.AdapterInternal as IPostBackDataHandler;
if(consumer == null) {
consumer = c as IPostBackDataHandler;
}
// Give a helpful error if the control is not a IPostBackDataHandler (ASURT 128532)
if (consumer == null) {
throw new HttpException(SR.GetString(SR.Postback_ctrl_not_found, controlID));
}
NameValueCollection postCollection = c.CalculateEffectiveValidateRequest() ? _requestValueCollection : _unvalidatedRequestValueCollection;
bool changed = consumer.LoadPostData(controlID, postCollection);
if (changed)
_changedPostDataConsumers.Add(c);
}
else {
if (fBeforeLoad) {
if (leftOverControlsRequiringPostBack == null)
leftOverControlsRequiringPostBack = new ArrayList();
leftOverControlsRequiringPostBack.Add(controlID);
}
}
}
_controlsRequiringPostBack = leftOverControlsRequiringPostBack;
}
}
// Operations like FindControl and LoadPostData call EnsureDataBound, which may fire up
// async model binding methods. Therefore we make ProcessPostData method to be async so that we can await
// async data bindings.
// The differences between ProcessPostData and ProcessPostDataAsync are:
// 1. ProcessPostDataAsync awaits GetWaitForPreviousStepCompletionAwaitable after FindControl();
// 2. ProcessPostDataAsync calls LoadPostDataAsync() instead of LoadPostData().
private async Task ProcessPostDataAsync(NameValueCollection postData, bool fBeforeLoad) {
if (_changedPostDataConsumers == null)
_changedPostDataConsumers = new ArrayList();
// identify controls that have postback data
if (postData != null) {
foreach (string postKey in postData) {
if (postKey != null) {
// Ignore system post fields
if (IsSystemPostField(postKey))
continue;
Control ctrl = null;
using (Context.SyncContext.AllowVoidAsyncOperationsBlock()) {
ctrl = FindControl(postKey);
await GetWaitForPreviousStepCompletionAwaitable();
}
if (ctrl == null) {
if (fBeforeLoad) {
// It was not found, so keep track of it for the post load attempt
if (_leftoverPostData == null)
_leftoverPostData = new NameValueCollection();
_leftoverPostData.Add(postKey, null);
}
continue;
}
IPostBackDataHandler consumer = ctrl.PostBackDataHandler;
// Ignore controls that are not IPostBackDataHandler (see ASURT 13581)
if (consumer == null) {
// If it's a IPostBackEventHandler (which doesn't implement IPostBackDataHandler),
// register it (ASURT 39040)
if (ctrl.PostBackEventHandler != null)
RegisterRequiresRaiseEvent(ctrl.PostBackEventHandler);
continue;
}
if (consumer != null) {
NameValueCollection postCollection = ctrl.CalculateEffectiveValidateRequest() ? _requestValueCollection : _unvalidatedRequestValueCollection;
bool changed = await LoadPostDataAsync(consumer, postKey, postCollection);
if (changed)
_changedPostDataConsumers.Add(ctrl);
}
// ensure controls are only notified of postback once
if (_controlsRequiringPostBack != null)
_controlsRequiringPostBack.Remove(postKey);
}
}
}
// Keep track of the leftover for the post-load attempt
ArrayList leftOverControlsRequiringPostBack = null;
// process controls that explicitly registered to be notified of postback
if (_controlsRequiringPostBack != null) {
foreach (string controlID in _controlsRequiringPostBack) {
Control c = null;
using (Context.SyncContext.AllowVoidAsyncOperationsBlock()) {
c = FindControl(controlID);
await GetWaitForPreviousStepCompletionAwaitable();
}
if (c != null) {
IPostBackDataHandler consumer = c.AdapterInternal as IPostBackDataHandler;
if (consumer == null) {
consumer = c as IPostBackDataHandler;
}
// Give a helpful error if the control is not a IPostBackDataHandler (ASURT 128532)
if (consumer == null) {
throw new HttpException(SR.GetString(SR.Postback_ctrl_not_found, controlID));
}
NameValueCollection postCollection = c.CalculateEffectiveValidateRequest() ? _requestValueCollection : _unvalidatedRequestValueCollection;
bool changed = await LoadPostDataAsync(consumer, controlID, postCollection);
if (changed)
_changedPostDataConsumers.Add(c);
}
else {
if (fBeforeLoad) {
if (leftOverControlsRequiringPostBack == null)
leftOverControlsRequiringPostBack = new ArrayList();
leftOverControlsRequiringPostBack.Add(controlID);
}
}
}
_controlsRequiringPostBack = leftOverControlsRequiringPostBack;
}
}
private async Task<bool> LoadPostDataAsync(IPostBackDataHandler consumer, string postKey, NameValueCollection postCollection) {
bool changed;
// ListControl family controls call EnsureDataBound in consumer.LoadPostData, which could be an async call in 4.6.
// LoadPostData, however, is a sync method, which means we cannot await EnsureDataBound in the method.
// To workaround this, for ListControl family controls, we call EnsureDataBound before we call into LoadPostData.
if (AppSettings.EnableAsyncModelBinding && consumer is ListControl) {
var listControl = consumer as ListControl;
listControl.SkipEnsureDataBoundInLoadPostData = true;
using (Context.SyncContext.AllowVoidAsyncOperationsBlock()) {
listControl.InternalEnsureDataBound();
await GetWaitForPreviousStepCompletionAwaitable();
}
}
changed = consumer.LoadPostData(postKey, postCollection);
return changed;
}
/*
* This method will raise change events for those controls that indicated
* during PostProcessData that their data has changed.
*/
// !! IMPORTANT !!
// If you change this method, also change RaiseChangedEventsAsync.
internal void RaiseChangedEvents() {
if (_changedPostDataConsumers != null) {
// fire change notifications for those controls that changed as a result of postback
for (int i=0; i < _changedPostDataConsumers.Count; i++) {
Control c = (Control)_changedPostDataConsumers[i];
IPostBackDataHandler changedPostDataConsumer;
if(c != null) {
changedPostDataConsumer = c.PostBackDataHandler;
}
else {
continue;
}
// Make sure the IPostBackDataHandler is still in the tree (ASURT 82495)
if (c != null && !c.IsDescendentOf(this))
continue;
if(c != null && c.PostBackDataHandler != null) {
changedPostDataConsumer.RaisePostDataChangedEvent();
}
}
}
}
// TAP version of RaiseChangedEvents.
// !! IMPORTANT !!
// If you change this method, also change RaiseChangedEvents.
internal async Task RaiseChangedEventsAsync() {
if (_changedPostDataConsumers != null) {
// fire change notifications for those controls that changed as a result of postback
for (int i = 0; i < _changedPostDataConsumers.Count; i++) {
Control c = (Control)_changedPostDataConsumers[i];
IPostBackDataHandler changedPostDataConsumer;
if (c != null) {
changedPostDataConsumer = c.PostBackDataHandler;
}
else {
continue;
}
// Make sure the IPostBackDataHandler is still in the tree (ASURT 82495)
if (c != null && !c.IsDescendentOf(this))
continue;
if (c != null && c.PostBackDataHandler != null) {
using (Context.SyncContext.AllowVoidAsyncOperationsBlock()) {
changedPostDataConsumer.RaisePostDataChangedEvent();
await GetWaitForPreviousStepCompletionAwaitable();
}
}
}
}
}
private void RaisePostBackEvent(NameValueCollection postData) {
// first check if there is a register control needing the postback event
// if we don't have one of those, fall back to the hidden field
// Note: this must happen before we look at postData[postEventArgumentID] (ASURT 50106)
if (_registeredControlThatRequireRaiseEvent != null) {
RaisePostBackEvent(_registeredControlThatRequireRaiseEvent, null);
}
else {
string eventSource = postData[postEventSourceID];
bool hasEventSource = (!String.IsNullOrEmpty(eventSource));
// VSWhidbey 204824: We also need to check if the postback is submitted
// by an autopostback control in mobile browsers which cannot set
// event target in markup
if (hasEventSource || AutoPostBackControl != null) {
Control sourceControl = null;
if (hasEventSource) {
sourceControl = FindControl(eventSource);
}
if (sourceControl != null && sourceControl.PostBackEventHandler != null) {
string eventArgument = postData[postEventArgumentID];
RaisePostBackEvent((sourceControl.PostBackEventHandler), eventArgument);
}
}
else {
Validate();
}
}
}
// Overridable method that just calls RaisePostBackEvent on controls (ASURT 48154)
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
protected virtual void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument) {
sourceControl.RaisePostBackEvent(eventArgument);
}
//
/// <devdoc>
/// <para>Registers a control as requiring an event to be raised when it is processed
/// on the page.</para>
/// </devdoc>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public virtual void RegisterRequiresRaiseEvent(IPostBackEventHandler control) {
_registeredControlThatRequireRaiseEvent = control;
}
// VSWhidbey 402530
// This property should be public. (DevDiv Bugs 161340)
public bool IsPostBackEventControlRegistered {
get {
return (_registeredControlThatRequireRaiseEvent != null);
}
}
/// <devdoc>
/// <para> Indicates whether page validation succeeded.</para>
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public bool IsValid {
get {
if (!_validated)
throw new HttpException(SR.GetString(SR.IsValid_Cant_Be_Called));
if (_validators != null) {
ValidatorCollection vc = Validators;
int count = vc.Count;
for (int i = 0; i < count; i++) {
if (!vc[i].IsValid) {
return false;
}
}
}
return true;
}
}
/// <devdoc>
/// <para>Gets a collection of all validation controls contained on the requested page.</para>
/// </devdoc>