|
//------------------------------------------------------------------------------
// <copyright file="ClientScriptManager.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.UI {
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;
using System.Text;
using System.Web.Compilation;
using System.Web.Handlers;
using System.Web.UI.WebControls;
using System.Web.Util;
using ExceptionUtil=System.Web.Util.ExceptionUtil;
using WebUtil = System.Web.Util;
using System.Security.Permissions;
using System.Reflection;
using System.Runtime.Serialization;
using System.Collections.Generic;
using System.Web.Security.Cryptography;
// The various types of client API's that can be registered
internal enum ClientAPIRegisterType {
WebFormsScript,
PostBackScript,
FocusScript,
ClientScriptBlocks,
ClientScriptBlocksWithoutTags,
ClientStartupScripts,
ClientStartupScriptsWithoutTags,
OnSubmitStatement,
ArrayDeclaration,
HiddenField,
ExpandoAttribute,
EventValidation,
}
public sealed class ClientScriptManager {
private const string IncludeScriptBegin = @"
<script src=""";
private const string IncludeScriptEnd = @""" type=""text/javascript""></script>";
internal const string ClientScriptStart = "\r\n<script type=\"text/javascript\">\r\n//<![CDATA[\r\n";
internal const string ClientScriptStartLegacy = "\r\n<script type=\"text/javascript\">\r\n<!--\r\n";
internal const string ClientScriptEnd = "//]]>\r\n</script>\r\n";
internal const string ClientScriptEndLegacy = "// -->\r\n</script>\r\n";
internal const string JscriptPrefix = "javascript:";
private const string _callbackFunctionName = "WebForm_DoCallback";
private const string _postbackOptionsFunctionName = "WebForm_DoPostBackWithOptions";
private const string _postBackFunctionName = "__doPostBack";
private const string PageCallbackScriptKey = "PageCallbackScript";
internal static IScriptResourceMapping _scriptResourceMapping;
private ListDictionary _registeredClientScriptBlocks;
private ArrayList _clientScriptBlocks;
private ListDictionary _registeredClientStartupScripts;
private ArrayList _clientStartupScripts;
private Dictionary<Assembly, Dictionary<String, Object>> _registeredResourcesToSuppress;
private bool _eventValidationFieldLoaded;
private ListDictionary _registeredOnSubmitStatements;
private IDictionary _registeredArrayDeclares;
private ListDictionary _registeredHiddenFields;
private ListDictionary _registeredControlsWithExpandoAttributes;
private IEventValidationProvider _eventValidationProvider;
private Page _owner;
internal ClientScriptManager(Page owner) {
_owner = owner;
}
internal bool HasRegisteredHiddenFields {
get {
return (_registeredHiddenFields != null && _registeredHiddenFields.Count > 0);
}
}
internal bool HasSubmitStatements {
get {
return (_registeredOnSubmitStatements != null && _registeredOnSubmitStatements.Count > 0);
}
}
internal Dictionary<Assembly, Dictionary<String, Object>> RegisteredResourcesToSuppress {
get {
if (_registeredResourcesToSuppress == null) {
_registeredResourcesToSuppress = new Dictionary<Assembly, Dictionary<String, Object>>();
}
return _registeredResourcesToSuppress;
}
}
private IEventValidationProvider EventValidationProvider {
get {
if (_eventValidationProvider == null) {
if (AppSettings.UseLegacyEventValidationCompatibility) {
_eventValidationProvider = new LegacyEventValidationProvider(this);
}
else {
_eventValidationProvider = new DefaultEventValidationProvider(this);
}
}
return _eventValidationProvider;
}
}
internal string GetEventValidationFieldValue() {
// Access the _eventValidationProvider field instead of the EventValidationProvider property so that we
// don't end up instantiating objects if not necessary.
if (_eventValidationProvider != null) {
object eventValidationStoreObject = _eventValidationProvider.GetEventValidationStoreObject();
if (eventValidationStoreObject != null) {
// Make cryptographically secure
IStateFormatter2 formatter = _owner.CreateStateFormatter();
return formatter.Serialize(eventValidationStoreObject, Purpose.WebForms_ClientScriptManager_EventValidation);
}
}
// If we got here, there was no store data.
return String.Empty;
}
public void RegisterForEventValidation(PostBackOptions options) {
RegisterForEventValidation(options.TargetControl.UniqueID, options.Argument);
}
public void RegisterForEventValidation(string uniqueId) {
RegisterForEventValidation(uniqueId, String.Empty);
}
public void RegisterForEventValidation(string uniqueId, string argument) {
// Step 1: argument and precondition checks
if (!_owner.EnableEventValidation || _owner.DesignMode) {
return;
}
// VSWhidbey 497632. Ignore if uniqueID is empty since the postback won't be valid anyway.
if (String.IsNullOrEmpty(uniqueId)) {
return;
}
if ((_owner.ControlState < ControlState.PreRendered) && (!_owner.IsCallback)) {
throw new InvalidOperationException(
SR.GetString(SR.ClientScriptManager_RegisterForEventValidation_Too_Early));
}
// Step 2: Add this tuple to the list
EventValidationProvider.RegisterForEventValidation(uniqueId, argument);
// Step 3: If there are any partial caching controls on the stack, forward the call to them
if (_owner.PartialCachingControlStack != null) {
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
c.RegisterForEventValidation(uniqueId, argument);
}
}
}
internal void SaveEventValidationField() {
string fieldValue = GetEventValidationFieldValue();
if (!String.IsNullOrEmpty(fieldValue)) {
RegisterHiddenField(Page.EventValidationPrefixID, fieldValue);
}
}
// Used by unobtrusive javascript validators to verify that a scriptresource mapping for jquery is registered
internal static void EnsureJqueryRegistered() {
if (_scriptResourceMapping != null) {
if (_scriptResourceMapping.GetDefinition("jquery", typeof(Page).Assembly) == null &&
_scriptResourceMapping.GetDefinition("jquery") == null) {
throw new InvalidOperationException(SR.GetString(SR.ClientScriptManager_JqueryNotRegistered));
}
}
}
private void EnsureEventValidationFieldLoaded() {
if (_eventValidationFieldLoaded) {
return;
}
_eventValidationFieldLoaded = true;
// Step 1: Read the event validation field
string unsafeField = null;
if (_owner.RequestValueCollection != null) {
unsafeField = _owner.RequestValueCollection[Page.EventValidationPrefixID];
}
if (String.IsNullOrEmpty(unsafeField)) {
return;
}
// Step 2: Decrypt the event validation field
IStateFormatter2 formatter = _owner.CreateStateFormatter();
object eventValidationField = null;
try {
eventValidationField = formatter.Deserialize(unsafeField, Purpose.WebForms_ClientScriptManager_EventValidation);
}
catch (Exception ex) {
// DevDiv #461378: Ignore validation errors for cross-page postbacks. Since the ValidateEvent method
// is most likely on the call stack right now, this will result in an event validation failure rather
// than a MAC validation failure.
if (!_owner.ShouldSuppressMacValidationException(ex)) {
ViewStateException.ThrowViewStateError(ex, unsafeField);
}
}
// Step 3: Load the event validation field into the appropriate provider
if (!EventValidationProvider.TryLoadEventValidationField(eventValidationField)) {
// Something went wrong while loading the incoming event validation object; the
// most likely cause is that it wasn't submitted with the correct ViewState.
ViewStateException.ThrowViewStateError(null, unsafeField);
}
}
public void ValidateEvent(string uniqueId) {
ValidateEvent(uniqueId, String.Empty);
}
public void ValidateEvent(string uniqueId, string argument) {
if (!_owner.EnableEventValidation) {
return;
}
if (String.IsNullOrEmpty(uniqueId)) {
throw new ArgumentException(SR.GetString(SR.Parameter_NullOrEmpty, "uniqueId"), "uniqueId");
}
EnsureEventValidationFieldLoaded();
// Go against the _eventValidationProvider field instead of the EventValidationProvider
// property to avoid the lazy instantiation code if not necessary.
if (_eventValidationProvider == null || !_eventValidationProvider.IsValid(uniqueId, argument)) {
throw new ArgumentException(SR.GetString(SR.ClientScriptManager_InvalidPostBackArgument));
}
}
internal void ClearHiddenFields() {
_registeredHiddenFields = null;
}
internal static ScriptKey CreateScriptKey(Type type, string key) {
return new ScriptKey(type, key);
}
internal static ScriptKey CreateScriptIncludeKey(Type type, string key, bool isResource) {
return new ScriptKey(type, key, true, isResource);
}
/// <devdoc>
/// Enables controls to obtain client-side script function that will cause
/// (when invoked) an out-of-band callback to the server
/// </devdoc>
public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context) {
return GetCallbackEventReference(control, argument, clientCallback, context, false);
}
public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context, bool useAsync) {
return GetCallbackEventReference(control, argument, clientCallback, context, null, useAsync);
}
/// <devdoc>
/// Enables controls to obtain client-side script function that will cause
/// (when invoked) an out-of-band callback to the server and allows the user to specify a client-side error callback
/// </devdoc>
public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync) {
if (control == null) {
throw new ArgumentNullException("control");
}
if (!(control is ICallbackEventHandler)) {
throw new InvalidOperationException(SR.GetString(SR.Page_CallBackTargetInvalid, control.UniqueID));
}
return GetCallbackEventReference("'" + control.UniqueID + "'", argument, clientCallback, context, clientErrorCallback, useAsync);
}
/// <devdoc>
/// Enables controls to obtain client-side script function that will cause
/// (when invoked) an out-of-band callback to the server and allows the user to specify a client-side error callback
/// </devdoc>
public string GetCallbackEventReference(string target, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync) {
_owner.RegisterWebFormsScript();
if (_owner.ClientSupportsJavaScript && (_owner.RequestInternal != null) && _owner.RequestInternal.Browser.SupportsCallback) {
RegisterStartupScript(typeof(Page), PageCallbackScriptKey, (((_owner.RequestInternal != null) &&
(String.Equals(_owner.RequestInternal.Url.Scheme, "https", StringComparison.OrdinalIgnoreCase))) ?
@"
var callBackFrameUrl='" + Util.QuoteJScriptString(GetWebResourceUrl(typeof(Page), "SmartNav.htm"), false) + @"';
WebForm_InitCallback();" :
@"
WebForm_InitCallback();"), true);
}
if (argument == null) {
argument = "null";
}
else if (argument.Length == 0) {
argument = "\"\"";
}
if (context == null) {
context = "null";
}
else if (context.Length == 0) {
context = "\"\"";
}
return _callbackFunctionName +
"(" +
target +
"," +
argument +
"," +
clientCallback +
"," +
context +
"," +
((clientErrorCallback == null) ? "null" : clientErrorCallback) +
"," +
(useAsync ? "true" : "false") +
")";
}
public string GetPostBackClientHyperlink(Control control, string argument) {
// We're using escapePercent=true here and false in Page
// because true in Page would be a breaking change:
// People may already be encoding percent characters before calling this,
// and we may double encode it.
// Our own classes and new code should almost always use the override with escapePercent=true.
return GetPostBackClientHyperlink(control, argument, true, false);
}
public string GetPostBackClientHyperlink(Control control, string argument, bool registerForEventValidation) {
// We're using escapePercent=true here and false in Page
// because true in Page would be a breaking change:
// People may already be encoding percent characters before calling this,
// and we may double encode it.
// Our own classes and new code should almost always use the override with escapePercent=true.
return GetPostBackClientHyperlink(control, argument, true, registerForEventValidation);
}
/// <devdoc>
/// <para>This returs a string that can be put in client event to post back to the named control</para>
/// </devdoc>
internal string GetPostBackClientHyperlink(Control control, string argument, bool escapePercent, bool registerForEventValidation) {
// Hyperlinks always need the language prefix
// If used in a hyperlink, the event argument needs to be escaped for % characters
// which will otherwise be interpreted as escape sequences (VSWhidbey 421874)
return JscriptPrefix + GetPostBackEventReference(control, argument, escapePercent, registerForEventValidation);
}
public string GetPostBackEventReference(Control control, string argument) {
return GetPostBackEventReference(control, argument, false, false);
}
public string GetPostBackEventReference(Control control, string argument, bool registerForEventValidation) {
return GetPostBackEventReference(control, argument, false, registerForEventValidation);
}
/*
* 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>
private string GetPostBackEventReference(Control control, string argument, bool forUrl, bool registerForEventValidation) {
if (control == null) {
throw new ArgumentNullException("control");
}
_owner.RegisterPostBackScript();
string controlID = control.UniqueID;
if (registerForEventValidation) {
RegisterForEventValidation(controlID, argument);
}
// VSWhidbey 475945
if (control.EnableLegacyRendering && _owner.IsInOnFormRender &&
controlID != null && controlID.IndexOf(Control.LEGACY_ID_SEPARATOR) >= 0) {
controlID = controlID.Replace(Control.LEGACY_ID_SEPARATOR, Control.ID_SEPARATOR);
}
// Split into 2 calls to String.Concat to improve performance.
// CLR is investigating whether this should be fixed at a lower level.
string postBackEventReference = _postBackFunctionName + "('" + controlID + "','";
// The argument needs to be quoted, in case in contains characters that
// can't be used in JScript strings (ASURT 71818).
postBackEventReference += Util.QuoteJScriptString(argument, forUrl) + "')";
return postBackEventReference;
}
/// <devdoc>
/// <para>Passes a parameter to the control that will do the postback processing on the
/// server.</para>
/// </devdoc>
public string GetPostBackEventReference(PostBackOptions options) {
return GetPostBackEventReference(options, false);
}
public string GetPostBackEventReference(PostBackOptions options, bool registerForEventValidation) {
if (options == null) {
throw new ArgumentNullException("options");
}
if (registerForEventValidation) {
RegisterForEventValidation(options);
}
StringBuilder builder = new StringBuilder();
bool shouldRenderPostBackReferenceString = false;
if (options.RequiresJavaScriptProtocol) {
builder.Append(JscriptPrefix);
}
if (options.AutoPostBack) {
builder.Append("setTimeout('");
}
// Use the old __doPostBack method if not using other postback features.
if (!options.PerformValidation && !options.TrackFocus && options.ClientSubmit &&
string.IsNullOrEmpty(options.ActionUrl)) {
string postbackRef = GetPostBackEventReference(options.TargetControl, options.Argument);
// Need to quote the string if auto posting back
if (options.AutoPostBack) {
builder.Append(Util.QuoteJScriptString(postbackRef));
builder.Append("', 0)");
}
else {
builder.Append(postbackRef);
}
return builder.ToString();
}
builder.Append(_postbackOptionsFunctionName);
builder.Append("(new WebForm_PostBackOptions(\"");
builder.Append(options.TargetControl.UniqueID);
builder.Append("\", ");
if (String.IsNullOrEmpty(options.Argument)) {
builder.Append("\"\", ");
}
else {
builder.Append("\"");
builder.Append(Util.QuoteJScriptString(options.Argument));
builder.Append("\", ");
}
if (options.PerformValidation) {
shouldRenderPostBackReferenceString = true;
builder.Append("true, ");
}
else {
builder.Append("false, ");
}
if (options.ValidationGroup != null && options.ValidationGroup.Length > 0) {
shouldRenderPostBackReferenceString = true;
builder.Append("\"");
builder.Append(options.ValidationGroup);
builder.Append("\", ");
}
else {
builder.Append("\"\", ");
}
if (options.ActionUrl != null && options.ActionUrl.Length > 0) {
shouldRenderPostBackReferenceString = true;
_owner.ContainsCrossPagePost = true;
builder.Append("\"");
builder.Append(Util.QuoteJScriptString(options.ActionUrl));
builder.Append("\", ");
}
else {
builder.Append("\"\", ");
}
if (options.TrackFocus) {
_owner.RegisterFocusScript();
shouldRenderPostBackReferenceString = true;
builder.Append("true, ");
}
else {
builder.Append("false, ");
}
if (options.ClientSubmit) {
shouldRenderPostBackReferenceString = true;
_owner.RegisterPostBackScript();
builder.Append("true))");
}
else {
builder.Append("false))");
}
if (options.AutoPostBack) {
builder.Append("', 0)");
}
string reference = null;
if (shouldRenderPostBackReferenceString) {
reference = builder.ToString();
_owner.RegisterWebFormsScript();
}
return reference;
}
/// <devdoc>
/// Gets a URL resource reference to a client-side resource
/// </devdoc>
public string GetWebResourceUrl(Type type, string resourceName) {
return GetWebResourceUrl(_owner, type, resourceName, false,
(_owner == null ? null : _owner.ScriptManager));
}
internal static string GetWebResourceUrl(Page owner, Type type, string resourceName, bool htmlEncoded, IScriptManager scriptManager) {
bool enableCdn = scriptManager != null && scriptManager.EnableCdn;
return GetWebResourceUrl(owner, type, resourceName, htmlEncoded, scriptManager, enableCdn);
}
internal static string GetWebResourceUrl(Page owner, Type type, string resourceName, bool htmlEncoded, IScriptManager scriptManager, bool enableCdn) {
if (type == null) {
throw new ArgumentNullException("type");
}
if (String.IsNullOrEmpty(resourceName)) {
throw new ArgumentNullException("resourceName");
}
if (owner != null && owner.DesignMode) {
ISite site = ((IComponent)owner).Site;
if (site != null) {
IResourceUrlGenerator urlGenerator = site.GetService(typeof(IResourceUrlGenerator)) as IResourceUrlGenerator;
if (urlGenerator != null) {
return urlGenerator.GetResourceUrl(type, resourceName);
}
}
return resourceName;
}
else {
return AssemblyResourceLoader.GetWebResourceUrl(type, resourceName, htmlEncoded, scriptManager, enableCdn: enableCdn);
}
}
/// <devdoc>
/// <para>Determines if the client script block is registered with the page.</para>
/// </devdoc>
public bool IsClientScriptBlockRegistered(string key) {
return IsClientScriptBlockRegistered(typeof(Page), key);
}
/// <devdoc>
/// <para>Determines if the client script block is registered with the page.</para>
/// </devdoc>
public bool IsClientScriptBlockRegistered(Type type, string key) {
if (type == null) {
throw new ArgumentNullException("type");
}
return (_registeredClientScriptBlocks != null
&& (_registeredClientScriptBlocks.Contains(CreateScriptKey(type, key))));
}
/// <devdoc>
/// <para>Determines if the onsubmit script is registered with the page.</para>
/// </devdoc>
public bool IsClientScriptIncludeRegistered(string key) {
return IsClientScriptIncludeRegistered(typeof(Page), key);
}
/// <devdoc>
/// <para>Determines if the onsubmit script is registered with the page.</para>
/// </devdoc>
public bool IsClientScriptIncludeRegistered(Type type, string key) {
if (type == null) {
throw new ArgumentNullException("type");
}
return (_registeredClientScriptBlocks != null
&& (_registeredClientScriptBlocks.Contains(CreateScriptIncludeKey(type, key, false))));
}
/// <devdoc>
/// <para>Determines if the client startup script is registered with the
/// page.</para>
/// </devdoc>
public bool IsStartupScriptRegistered(string key) {
return IsStartupScriptRegistered(typeof(Page), key);
}
/// <devdoc>
/// <para>Determines if the client startup script is registered with the
/// page.</para>
/// </devdoc>
public bool IsStartupScriptRegistered(Type type, string key) {
if (type == null) {
throw new ArgumentNullException("type");
}
return (_registeredClientStartupScripts != null
&& (_registeredClientStartupScripts.Contains(CreateScriptKey(type, key))));
}
/// <devdoc>
/// <para>Determines if the onsubmit script is registered with the page.</para>
/// </devdoc>
public bool IsOnSubmitStatementRegistered(string key) {
return IsOnSubmitStatementRegistered(typeof(Page), key);
}
/// <devdoc>
/// <para>Determines if the onsubmit script is registered with the page.</para>
/// </devdoc>
public bool IsOnSubmitStatementRegistered(Type type, string key) {
if (type == null) {
throw new ArgumentNullException("type");
}
return (_registeredOnSubmitStatements != null
&& (_registeredOnSubmitStatements.Contains(CreateScriptKey(type, 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>
public void RegisterArrayDeclaration(string arrayName, string arrayValue) {
if (arrayName == null) {
throw new ArgumentNullException("arrayName");
}
if (_registeredArrayDeclares == null) {
_registeredArrayDeclares = new ListDictionary();
}
if (!_registeredArrayDeclares.Contains(arrayName)) {
_registeredArrayDeclares[arrayName] = new ArrayList();
}
ArrayList elements = (ArrayList)_registeredArrayDeclares[arrayName];
elements.Add(arrayValue);
// If there are any partial caching controls on the stack, forward the call to them
if (_owner.PartialCachingControlStack != null) {
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
c.RegisterArrayDeclaration(arrayName, arrayValue);
}
}
}
// RegisterArrayDeclaration implementation that supports partial rendering.
internal void RegisterArrayDeclaration(Control control, string arrayName, string arrayValue) {
IScriptManager scriptManager = _owner.ScriptManager;
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
scriptManager.RegisterArrayDeclaration(control, arrayName, arrayValue);
}
else {
RegisterArrayDeclaration(arrayName, arrayValue);
}
}
public void RegisterExpandoAttribute(string controlId, string attributeName, string attributeValue) {
RegisterExpandoAttribute(controlId, attributeName, attributeValue, true);
}
public void RegisterExpandoAttribute(string controlId, string attributeName, string attributeValue, bool encode) {
// check paramters
WebUtil.StringUtil.CheckAndTrimString(controlId, "controlId");
WebUtil.StringUtil.CheckAndTrimString(attributeName, "attributeName");
ListDictionary expandoAttributes = null;
if (_registeredControlsWithExpandoAttributes == null) {
_registeredControlsWithExpandoAttributes = new ListDictionary(StringComparer.Ordinal);
}
else {
expandoAttributes = (ListDictionary)_registeredControlsWithExpandoAttributes[controlId];
}
if (expandoAttributes == null) {
expandoAttributes = new ListDictionary(StringComparer.Ordinal);
_registeredControlsWithExpandoAttributes.Add(controlId, expandoAttributes);
}
if (encode) {
attributeValue = Util.QuoteJScriptString(attributeValue);
}
expandoAttributes.Add(attributeName, attributeValue);
// If there are any partial caching controls on the stack, forward the call to them
if (_owner.PartialCachingControlStack != null) {
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
c.RegisterExpandoAttribute(controlId, attributeName, attributeValue);
}
}
}
// RegisterExpandoAttribute implementation that supports partial rendering.
internal void RegisterExpandoAttribute(Control control, string controlId, string attributeName, string attributeValue, bool encode) {
IScriptManager scriptManager = _owner.ScriptManager;
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
scriptManager.RegisterExpandoAttribute(control, controlId, attributeName, attributeValue, encode);
}
else {
RegisterExpandoAttribute(controlId, attributeName, attributeValue, encode);
}
}
/// <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>
public void RegisterHiddenField(string hiddenFieldName,
string hiddenFieldInitialValue) {
if (hiddenFieldName == null) {
throw new ArgumentNullException("hiddenFieldName");
}
if (_registeredHiddenFields == null)
_registeredHiddenFields = new ListDictionary();
if (!_registeredHiddenFields.Contains(hiddenFieldName))
_registeredHiddenFields.Add(hiddenFieldName, hiddenFieldInitialValue);
if (_owner._hiddenFieldsToRender == null) {
_owner._hiddenFieldsToRender = new Dictionary<String, String>();
}
_owner._hiddenFieldsToRender[hiddenFieldName] = hiddenFieldInitialValue;
// If there are any partial caching controls on the stack, forward the call to them
if (_owner.PartialCachingControlStack != null) {
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
c.RegisterHiddenField(hiddenFieldName, hiddenFieldInitialValue);
}
}
}
// RegisterHiddenField implementation that supports partial rendering.
internal void RegisterHiddenField(Control control, string hiddenFieldName, string hiddenFieldValue) {
IScriptManager scriptManager = _owner.ScriptManager;
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
scriptManager.RegisterHiddenField(control, hiddenFieldName, hiddenFieldValue);
}
else {
RegisterHiddenField(hiddenFieldName, hiddenFieldValue);
}
}
/// <devdoc>
/// Prevents controls from sending duplicate blocks of
/// client-side script to the client. Any script blocks with the same type and key
/// values are considered duplicates.</para>
/// </devdoc>
public void RegisterClientScriptBlock(Type type, string key, string script) {
RegisterClientScriptBlock(type, key, script, false);
}
/// <devdoc>
/// Prevents controls from sending duplicate blocks of
/// client-side script to the client. Any script blocks with the same type and key
/// values are considered duplicates.</para>
/// </devdoc>
public void RegisterClientScriptBlock(Type type, string key, string script, bool addScriptTags) {
if (type == null) {
throw new ArgumentNullException("type");
}
if (addScriptTags) {
RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientScriptBlocksWithoutTags);
}
else {
RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientScriptBlocks);
}
}
// RegisterClientScriptBlock implementation that supports partial rendering.
internal void RegisterClientScriptBlock(Control control, Type type, string key, string script, bool addScriptTags) {
IScriptManager scriptManager = _owner.ScriptManager;
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
scriptManager.RegisterClientScriptBlock(control, type, key, script, addScriptTags);
}
else {
RegisterClientScriptBlock(type, key, script, addScriptTags);
}
}
/// <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>
public void RegisterClientScriptInclude(string key, string url) {
RegisterClientScriptInclude(typeof(Page), key, url);
}
/// <devdoc>
/// Prevents controls from sending duplicate blocks of
/// client-side script to the client. Any script blocks with the same type and key
/// values are considered duplicates.</para>
/// </devdoc>
public void RegisterClientScriptInclude(Type type, string key, string url) {
RegisterClientScriptInclude(type, key, url, false);
}
internal void RegisterClientScriptInclude(Type type, string key, string url, bool isResource) {
if (type == null) {
throw new ArgumentNullException("type");
}
if (String.IsNullOrEmpty(url)) {
throw ExceptionUtil.ParameterNullOrEmpty("url");
}
// VSWhidbey 499036: encode the url
string script = IncludeScriptBegin + HttpUtility.HtmlAttributeEncode(url) + IncludeScriptEnd;
RegisterScriptBlock(CreateScriptIncludeKey(type, key, isResource), script, ClientAPIRegisterType.ClientScriptBlocks);
}
// RegisterClientScriptInclude implementation that supports partial rendering.
internal void RegisterClientScriptInclude(Control control, Type type, string key, string url) {
IScriptManager scriptManager = _owner.ScriptManager;
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
scriptManager.RegisterClientScriptInclude(control, type, key, url);
}
else {
RegisterClientScriptInclude(type, key, url);
}
}
/// <devdoc>
/// </devdoc>
public void RegisterClientScriptResource(Type type, string resourceName) {
if (type == null) {
throw new ArgumentNullException("type");
}
RegisterClientScriptInclude(type, resourceName, GetWebResourceUrl(type, resourceName), true);
}
// RegisterClientScriptResource implementation that supports partial rendering.
internal void RegisterClientScriptResource(Control control, Type type, string resourceName) {
IScriptManager scriptManager = _owner.ScriptManager;
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
scriptManager.RegisterClientScriptResource(control, type, resourceName);
}
else {
RegisterClientScriptResource(type, resourceName);
}
}
internal void RegisterDefaultButtonScript(Control button, HtmlTextWriter writer, bool useAddAttribute) {
_owner.RegisterWebFormsScript();
if (_owner.EnableLegacyRendering) {
if (useAddAttribute) {
writer.AddAttribute("language", "javascript", false);
}
else {
writer.WriteAttribute("language", "javascript", false);
}
}
string keyPress = "javascript:return WebForm_FireDefaultButton(event, '" + button.ClientID + "')";
if (useAddAttribute) {
writer.AddAttribute("onkeypress", keyPress);
}
else {
writer.WriteAttribute("onkeypress", keyPress);
}
}
/// <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>
public void RegisterOnSubmitStatement(Type type, string key, string script) {
if (type == null) {
throw new ArgumentNullException("type");
}
RegisterOnSubmitStatementInternal(CreateScriptKey(type, key), script);
}
// RegisterOnSubmitStatement implementation that supports partial rendering.
internal void RegisterOnSubmitStatement(Control control, Type type, string key, string script) {
IScriptManager scriptManager = _owner.ScriptManager;
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
scriptManager.RegisterOnSubmitStatement(control, type, key, script);
}
else {
RegisterOnSubmitStatement(type, key, script);
}
}
internal void RegisterOnSubmitStatementInternal(ScriptKey key, string script) {
if (String.IsNullOrEmpty(script)) {
throw ExceptionUtil.ParameterNullOrEmpty("script");
}
if (_registeredOnSubmitStatements == null)
_registeredOnSubmitStatements = new ListDictionary();
// Make sure the script block ends in a semicolon
int index = script.Length - 1;
while ((index >= 0) && Char.IsWhiteSpace(script, index)) {
index--;
}
if ((index >= 0) && (script[index] != ';')) {
script = script.Substring(0, index + 1) + ";" + script.Substring(index + 1);
}
if (!_registeredOnSubmitStatements.Contains(key))
_registeredOnSubmitStatements.Add(key, script);
// If there are any partial caching controls on the stack, forward the call to them
if (_owner.PartialCachingControlStack != null) {
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
c.RegisterOnSubmitStatement(key, script);
}
}
}
internal void RegisterScriptBlock(ScriptKey key, string script, ClientAPIRegisterType type) {
// Call RegisterScriptBlock with the correct collection based on the blockType
switch (type) {
case ClientAPIRegisterType.ClientScriptBlocks:
RegisterScriptBlock(key, script, ref _registeredClientScriptBlocks, ref _clientScriptBlocks, false);
break;
case ClientAPIRegisterType.ClientScriptBlocksWithoutTags:
RegisterScriptBlock(key, script, ref _registeredClientScriptBlocks, ref _clientScriptBlocks, true);
break;
case ClientAPIRegisterType.ClientStartupScripts:
RegisterScriptBlock(key, script, ref _registeredClientStartupScripts, ref _clientStartupScripts, false);
break;
case ClientAPIRegisterType.ClientStartupScriptsWithoutTags:
RegisterScriptBlock(key, script, ref _registeredClientStartupScripts, ref _clientStartupScripts, true);
break;
default:
Debug.Assert(false);
break;
}
// If there are any partial caching controls on the stack, forward the call to them
if (_owner.PartialCachingControlStack != null) {
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
c.RegisterScriptBlock(type, key, script);
}
}
}
private void RegisterScriptBlock(ScriptKey key, string script, ref ListDictionary scriptBlocks, ref ArrayList scriptList, bool needsScriptTags) {
if (scriptBlocks == null) {
scriptBlocks = new ListDictionary();
scriptList = new ArrayList();
}
if (!scriptBlocks.Contains(key)) {
Tuple<ScriptKey, String, Boolean> entry = new Tuple<ScriptKey, String, Boolean>(key, script, needsScriptTags);
scriptBlocks.Add(key, null);
scriptList.Add(entry);
}
}
/// <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 type and key
/// value are considered duplicates.
/// </para>
/// </devdoc>
public void RegisterStartupScript(Type type, string key, string script) {
RegisterStartupScript(type, key, script, false);
}
/// <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 type and key
/// value are considered duplicates.
/// </para>
/// </devdoc>
public void RegisterStartupScript(Type type, string key, string script, bool addScriptTags) {
if (type == null) {
throw new ArgumentNullException("type");
}
if (addScriptTags) {
RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientStartupScriptsWithoutTags);
}
else {
RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientStartupScripts);
}
}
// RegisterStartupScript implementation that supports partial rendering.
internal void RegisterStartupScript(Control control, Type type, string key, string script, bool addScriptTags) {
IScriptManager scriptManager = _owner.ScriptManager;
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
scriptManager.RegisterStartupScript(control, type, key, script, addScriptTags);
}
else {
RegisterStartupScript(type, key, script, addScriptTags);
}
}
internal void RenderArrayDeclares(HtmlTextWriter writer) {
if (_registeredArrayDeclares == null || _registeredArrayDeclares.Count == 0) {
return;
}
writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart);
// Write out each array
IDictionaryEnumerator arrays = _registeredArrayDeclares.GetEnumerator();
while (arrays.MoveNext()) {
// Write the declaration
writer.Write("var ");
writer.Write(arrays.Key);
writer.Write(" = new Array(");
// Write each element
IEnumerator elements = ((ArrayList)arrays.Value).GetEnumerator();
bool first = true;
while (elements.MoveNext()) {
if (first) {
first = false;
}
else {
writer.Write(", ");
}
writer.Write(elements.Current);
}
// Close the declaration
writer.WriteLine(");");
}
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
}
internal void RenderExpandoAttribute(HtmlTextWriter writer) {
if (_registeredControlsWithExpandoAttributes == null ||
_registeredControlsWithExpandoAttributes.Count == 0) {
return;
}
writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart);
foreach (DictionaryEntry controlEntry in _registeredControlsWithExpandoAttributes) {
string controlId = (string)controlEntry.Key;
writer.Write("var ");
writer.Write(controlId);
writer.Write(" = document.all ? document.all[\"");
writer.Write(controlId);
writer.Write("\"] : document.getElementById(\"");
writer.Write(controlId);
writer.WriteLine("\");");
ListDictionary expandoAttributes = (ListDictionary)controlEntry.Value;
Debug.Assert(expandoAttributes != null && expandoAttributes.Count > 0);
foreach (DictionaryEntry expandoAttribute in expandoAttributes) {
writer.Write(controlId);
writer.Write(".");
writer.Write(expandoAttribute.Key);
if (expandoAttribute.Value == null) {
// VSWhidbey 382151 Render out null string for nulls
writer.WriteLine(" = null;");
}
else {
writer.Write(" = \"");
writer.Write(expandoAttribute.Value);
writer.WriteLine("\";");
}
}
}
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
}
internal void RenderHiddenFields(HtmlTextWriter writer) {
if (_registeredHiddenFields == null || _registeredHiddenFields.Count == 0) {
return;
}
foreach (DictionaryEntry entry in _registeredHiddenFields) {
string entryKey = (string)entry.Key;
if (entryKey == null) {
entryKey = String.Empty;
}
writer.WriteLine();
writer.Write("<input type=\"hidden\" name=\"");
writer.Write(entryKey);
writer.Write("\" id=\"");
writer.Write(entryKey);
writer.Write("\" value=\"");
HttpUtility.HtmlEncode((string)entry.Value, writer);
writer.Write("\" />");
}
ClearHiddenFields();
}
internal void RenderClientScriptBlocks(HtmlTextWriter writer) {
bool inScriptBlock = false;
if (_clientScriptBlocks != null) {
inScriptBlock = RenderRegisteredScripts(writer, _clientScriptBlocks, true);
}
// Emit the onSubmit function, in necessary
if (!String.IsNullOrEmpty(_owner.ClientOnSubmitEvent) && _owner.ClientSupportsJavaScript) {
// If we were already inside a script tag, don't emit a new open script tag
if (!inScriptBlock) {
writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart);
}
writer.Write(@"function WebForm_OnSubmit() {
");
if (_registeredOnSubmitStatements != null) {
foreach (string s in _registeredOnSubmitStatements.Values) {
writer.Write(s);
}
}
writer.WriteLine(@"
return true;
}");
// We always need to close the script tag
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
}
// If there was no onSubmit function, close the script tag if needed
else if (inScriptBlock) {
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
}
}
internal void RenderClientStartupScripts(HtmlTextWriter writer) {
if (_clientStartupScripts != null) {
bool inScriptBlock = RenderRegisteredScripts(writer, _clientStartupScripts, false);
// Close the script tag if needed
if (inScriptBlock) {
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
}
}
}
private bool RenderRegisteredScripts(HtmlTextWriter writer, ArrayList scripts, bool checkForScriptManagerRegistrations) {
writer.WriteLine();
bool inScriptBlock = false;
checkForScriptManagerRegistrations &= (_registeredResourcesToSuppress != null);
// Write out each registered script block
foreach (Tuple<ScriptKey, String, Boolean> entry in scripts) {
if (checkForScriptManagerRegistrations) {
ScriptKey scriptKey = entry.Item1;
if (scriptKey.IsResource) {
Dictionary<String, Object> resources;
if (_registeredResourcesToSuppress.TryGetValue(scriptKey.Assembly, out resources)
&& resources.ContainsKey(scriptKey.Key)) {
// this is a suppressed resource
continue;
}
}
}
if (entry.Item3) {
if (!inScriptBlock) {
// If we need script tags and we're not in a script tag, emit a start script tag
writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart);
inScriptBlock = true;
}
}
else if (inScriptBlock) {
// If we don't need script tags, and we're in a script tag, emit an end script tag
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
inScriptBlock = false;
}
writer.Write(entry.Item2);
}
return inScriptBlock;
}
internal void RenderWebFormsScript(HtmlTextWriter writer) {
const string webFormScript = "WebForms.js";
if (_registeredResourcesToSuppress != null) {
Dictionary<String, Object> systemWebResources;
if (_registeredResourcesToSuppress.TryGetValue(AssemblyResourceLoader.GetAssemblyFromType(typeof(Page)),
out systemWebResources) &&
systemWebResources.ContainsKey("WebForms.js")) {
return;
}
}
writer.Write(IncludeScriptBegin);
writer.Write(GetWebResourceUrl(_owner, typeof(Page), webFormScript, htmlEncoded: true, scriptManager: _owner.ScriptManager));
writer.Write(IncludeScriptEnd);
// Render the fallback script for WebForm.js
if (_owner.ScriptManager != null && _owner.ScriptManager.EnableCdn && _owner.ScriptManager.EnableCdnFallback) {
var localPath = GetWebResourceUrl(_owner, typeof(Page), webFormScript, htmlEncoded: true, scriptManager: _owner.ScriptManager, enableCdn: false);
if (!String.IsNullOrEmpty(localPath)) {
writer.Write(ClientScriptStart);
writer.Write(@"window.WebForm_PostBackOptions||document.write('<script type=""text/javascript"" src=""" + localPath + @"""><\/script>');");
writer.Write(ClientScriptEnd);
}
}
writer.WriteLine();
}
private interface IEventValidationProvider {
// Gets an object that - when serialized and encrypted - is the outbound __EVENTVALIDATION field value.
object GetEventValidationStoreObject();
// Returns a value denoting whether this (uniqueId, argument) tuple is valid for the current postback.
bool IsValid(string uniqueId, string argument);
// Registers the tuple (uniqueId, argument) as a valid event for the next postback.
void RegisterForEventValidation(string uniqueId, string argument);
// Given the deserialized form of an incoming __EVENTVALIDATION field, tries to load the valid
// event references for this postback. Returns true on success, false on failure.
bool TryLoadEventValidationField(object eventValidationField);
}
// provides a more secure implementation of event validation (fix for DevDiv #233564)
private sealed class DefaultEventValidationProvider : IEventValidationProvider {
private readonly ClientScriptManager _clientScriptManager;
private EventValidationStore _inboundEvents; // events which are valid for the current postback
private EventValidationStore _outboundEvents; // events which will be valid on the next postback
internal DefaultEventValidationProvider(ClientScriptManager clientScriptManager) {
_clientScriptManager = clientScriptManager;
}
public object GetEventValidationStoreObject() {
// We only produce the object to be serialized if there is data in the store
if (_outboundEvents != null && _outboundEvents.Count > 0) {
return _outboundEvents;
}
else {
return null;
}
}
public bool IsValid(string uniqueId, string argument) {
return _inboundEvents != null && _inboundEvents.Contains(uniqueId, argument);
}
public void RegisterForEventValidation(string uniqueId, string argument) {
if (_outboundEvents == null) {
if (_clientScriptManager._owner.IsCallback) {
_clientScriptManager.EnsureEventValidationFieldLoaded();
// _outboundEvents could have been initialized by the call to EnsureEventValidationFieldLoaded.
if (_outboundEvents == null) {
_outboundEvents = new EventValidationStore();
}
}
else {
// Make a new store object and tie it to the outbound __VIEWSTATE field.
// (This is the only field which can have a null/empty 'target'.)
_outboundEvents = new EventValidationStore();
_outboundEvents.Add(null, _clientScriptManager._owner.ClientState);
}
}
_outboundEvents.Add(uniqueId, argument);
}
public bool TryLoadEventValidationField(object eventValidationField) {
EventValidationStore validatedIncomingEvents = eventValidationField as EventValidationStore;
if (validatedIncomingEvents == null || validatedIncomingEvents.Count < 1) {
return true; // empty collection is not an error condition
}
Debug.Assert(_outboundEvents == null);
string viewStateString = _clientScriptManager._owner.RequestViewStateString;
if (!validatedIncomingEvents.Contains(null, viewStateString)) {
return false; // error: this event validation store isn't associated with the incoming __VIEWSTATE
}
_inboundEvents = validatedIncomingEvents;
if (_clientScriptManager._owner.IsCallback) {
// Seed the outbound provider with the valid inbound values; clone so that any outbound values
// added during page processing aren't accidentally treated as valid inbound values.
EventValidationStore clonedEventValidationStore = validatedIncomingEvents.Clone();
_outboundEvents = clonedEventValidationStore;
}
return true;
}
}
// provides the legacy implementation of event validation (before DevDiv #233564)
private sealed class LegacyEventValidationProvider : IEventValidationProvider {
private readonly ClientScriptManager _clientScriptManager;
private ArrayList _validEventReferences;
private HybridDictionary _clientPostBackValidatedEventTable;
internal LegacyEventValidationProvider(ClientScriptManager clientScriptManager) {
_clientScriptManager = clientScriptManager;
}
private static int ComputeHashKey(String uniqueId, String argument) {
if (String.IsNullOrEmpty(argument)) {
return StringUtil.GetStringHashCode(uniqueId);
}
return StringUtil.GetStringHashCode(uniqueId) ^ StringUtil.GetStringHashCode(argument);
}
public object GetEventValidationStoreObject() {
// We only produce the object to be serialized if there is data in the store
if (_validEventReferences != null && _validEventReferences.Count > 0) {
return _validEventReferences;
}
else {
return null;
}
}
public bool IsValid(string uniqueId, string argument) {
if (_clientPostBackValidatedEventTable == null) {
return false;
}
#if DEBUGEVENTVALIDATION
String hashCode = uniqueId + "@" + argument;
#else
int hashCode = ComputeHashKey(uniqueId, argument);
#endif //DEBUGEVENTVALIDATION
return _clientPostBackValidatedEventTable.Contains(hashCode);
}
public void RegisterForEventValidation(string uniqueId, string argument) {
#if DEBUGEVENTVALIDATION
string key = uniqueId + "@" + argument;
#else
int key = ComputeHashKey(uniqueId, argument);
#endif //DEBUGEVENTVALIDATION
string stateString = _clientScriptManager._owner.ClientState;
if (stateString == null) {
stateString = String.Empty;
}
if (_validEventReferences == null) {
if (_clientScriptManager._owner.IsCallback) {
_clientScriptManager.EnsureEventValidationFieldLoaded();
if (_validEventReferences == null) {
_validEventReferences = new ArrayList();
}
}
else {
_validEventReferences = new ArrayList();
_validEventReferences.Add(
StringUtil.GetStringHashCode(stateString));
}
}
#if DEBUGEVENTVALIDATION
Debug.Assert(!_validEventReferences.Contains(key));
#endif //DEBUGEVENTVALIDATION
_validEventReferences.Add(key);
}
public bool TryLoadEventValidationField(object eventValidationField) {
ArrayList validatedClientEvents = eventValidationField as ArrayList;
if (validatedClientEvents == null || validatedClientEvents.Count < 1) {
return true; // empty collection is not an error condition
}
Debug.Assert(_clientPostBackValidatedEventTable == null);
int viewStateHashCode = (int)validatedClientEvents[0];
string viewStateString = _clientScriptManager._owner.RequestViewStateString;
if (viewStateHashCode != StringUtil.GetStringHashCode(viewStateString)) {
return false; // hash mismatch is an error condition
}
_clientPostBackValidatedEventTable = new HybridDictionary(validatedClientEvents.Count - 1, true);
// Ignore the first item in the arrayList, which is the controlstate
for (int index = 1; index < validatedClientEvents.Count; index++) {
#if DEBUGEVENTVALIDATION
string hashKey = (string)validatedClientEvents[index];
#else
int hashKey = (int)validatedClientEvents[index];
#endif //DEBUGEVENTVALIDATION
_clientPostBackValidatedEventTable[hashKey] = null;
}
if (_clientScriptManager._owner.IsCallback) {
_validEventReferences = validatedClientEvents;
}
return true;
}
}
}
[Serializable]
internal class ScriptKey {
[NonSerialized]
private Type _type;
private string _typeNameForSerialization;
private string _key;
private bool _isInclude;
private bool _isResource;
internal ScriptKey(Type type, string key) : this(type, key, false, false) {
}
internal ScriptKey(Type type, string key, bool isInclude, bool isResource) {
Debug.Assert(type != null);
_type = type;
// To treat nulls the same as empty strings, make them empty string.
if (key == null) {
key = String.Empty;
}
_key = key;
_isInclude = isInclude;
_isResource = isResource;
}
public Assembly Assembly {
get {
return _type == null ? null : AssemblyResourceLoader.GetAssemblyFromType(_type);
}
}
public bool IsResource {
get {
return _isResource;
}
}
public string Key {
get {
return _key;
}
}
public override int GetHashCode() {
return WebUtil.HashCodeCombiner.CombineHashCodes(_type.GetHashCode(), _key.GetHashCode(),
_isInclude.GetHashCode());
}
public override bool Equals(object o) {
ScriptKey key = (ScriptKey)o;
return (key._type == _type) && (key._key == _key) && (key._isInclude == _isInclude);
}
[OnSerializing()]
private void OnSerializingMethod(StreamingContext context) {
// create a string representation of _type
_typeNameForSerialization = System.Web.UI.Util.GetAssemblyQualifiedTypeName(_type);
}
[OnDeserialized()]
private void OnDeserializedMethod(StreamingContext context) {
// re-create _type from its string representation
_type = BuildManager.GetType(_typeNameForSerialization, true /*throwOnFail*/, false /*ignoreCase*/);
}
}
}
|