1 //------------------------------------------------------------------------------ 2 // <copyright file="ClientScriptManager.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 namespace System.Web.UI { 8 using System; 9 using System.ComponentModel; 10 using System.ComponentModel.Design; 11 using System.Collections; 12 using System.Collections.Specialized; 13 using System.Globalization; 14 using System.Text; 15 using System.Web.Compilation; 16 using System.Web.Handlers; 17 using System.Web.UI.WebControls; 18 using System.Web.Util; 19 using ExceptionUtil=System.Web.Util.ExceptionUtil; 20 using WebUtil = System.Web.Util; 21 using System.Security.Permissions; 22 using System.Reflection; 23 using System.Runtime.Serialization; 24 using System.Collections.Generic; 25 using System.Web.Security.Cryptography; 26 27 // The various types of client API's that can be registered 28 internal enum ClientAPIRegisterType { 29 WebFormsScript, 30 PostBackScript, 31 FocusScript, 32 ClientScriptBlocks, 33 ClientScriptBlocksWithoutTags, 34 ClientStartupScripts, 35 ClientStartupScriptsWithoutTags, 36 OnSubmitStatement, 37 ArrayDeclaration, 38 HiddenField, 39 ExpandoAttribute, 40 EventValidation, 41 } 42 43 public sealed class ClientScriptManager { 44 private const string IncludeScriptBegin = @" 45 <script src="""; 46 private const string IncludeScriptEnd = @""" type=""text/javascript""></script>"; 47 internal const string ClientScriptStart = "\r\n<script type=\"text/javascript\">\r\n//<![CDATA[\r\n"; 48 internal const string ClientScriptStartLegacy = "\r\n<script type=\"text/javascript\">\r\n<!--\r\n"; 49 internal const string ClientScriptEnd = "//]]>\r\n</script>\r\n"; 50 internal const string ClientScriptEndLegacy = "// -->\r\n</script>\r\n"; 51 internal const string JscriptPrefix = "javascript:"; 52 53 private const string _callbackFunctionName = "WebForm_DoCallback"; 54 private const string _postbackOptionsFunctionName = "WebForm_DoPostBackWithOptions"; 55 private const string _postBackFunctionName = "__doPostBack"; 56 private const string PageCallbackScriptKey = "PageCallbackScript"; 57 58 internal static IScriptResourceMapping _scriptResourceMapping; 59 60 private ListDictionary _registeredClientScriptBlocks; 61 private ArrayList _clientScriptBlocks; 62 private ListDictionary _registeredClientStartupScripts; 63 private ArrayList _clientStartupScripts; 64 private Dictionary<Assembly, Dictionary<String, Object>> _registeredResourcesToSuppress; 65 private bool _eventValidationFieldLoaded; 66 67 private ListDictionary _registeredOnSubmitStatements; 68 69 private IDictionary _registeredArrayDeclares; 70 private ListDictionary _registeredHiddenFields; 71 private ListDictionary _registeredControlsWithExpandoAttributes; 72 73 private IEventValidationProvider _eventValidationProvider; 74 75 private Page _owner; 76 ClientScriptManager(Page owner)77 internal ClientScriptManager(Page owner) { 78 _owner = owner; 79 } 80 81 internal bool HasRegisteredHiddenFields { 82 get { 83 return (_registeredHiddenFields != null && _registeredHiddenFields.Count > 0); 84 } 85 } 86 87 internal bool HasSubmitStatements { 88 get { 89 return (_registeredOnSubmitStatements != null && _registeredOnSubmitStatements.Count > 0); 90 } 91 } 92 93 internal Dictionary<Assembly, Dictionary<String, Object>> RegisteredResourcesToSuppress { 94 get { 95 if (_registeredResourcesToSuppress == null) { 96 _registeredResourcesToSuppress = new Dictionary<Assembly, Dictionary<String, Object>>(); 97 } 98 return _registeredResourcesToSuppress; 99 } 100 } 101 102 private IEventValidationProvider EventValidationProvider { 103 get { 104 if (_eventValidationProvider == null) { 105 if (AppSettings.UseLegacyEventValidationCompatibility) { 106 _eventValidationProvider = new LegacyEventValidationProvider(this); 107 } 108 else { 109 _eventValidationProvider = new DefaultEventValidationProvider(this); 110 } 111 } 112 return _eventValidationProvider; 113 } 114 } 115 GetEventValidationFieldValue()116 internal string GetEventValidationFieldValue() { 117 // Access the _eventValidationProvider field instead of the EventValidationProvider property so that we 118 // don't end up instantiating objects if not necessary. 119 if (_eventValidationProvider != null) { 120 object eventValidationStoreObject = _eventValidationProvider.GetEventValidationStoreObject(); 121 if (eventValidationStoreObject != null) { 122 // Make cryptographically secure 123 IStateFormatter2 formatter = _owner.CreateStateFormatter(); 124 return formatter.Serialize(eventValidationStoreObject, Purpose.WebForms_ClientScriptManager_EventValidation); 125 } 126 } 127 128 // If we got here, there was no store data. 129 return String.Empty; 130 } 131 RegisterForEventValidation(PostBackOptions options)132 public void RegisterForEventValidation(PostBackOptions options) { 133 RegisterForEventValidation(options.TargetControl.UniqueID, options.Argument); 134 } 135 RegisterForEventValidation(string uniqueId)136 public void RegisterForEventValidation(string uniqueId) { 137 RegisterForEventValidation(uniqueId, String.Empty); 138 } 139 RegisterForEventValidation(string uniqueId, string argument)140 public void RegisterForEventValidation(string uniqueId, string argument) { 141 // Step 1: argument and precondition checks 142 if (!_owner.EnableEventValidation || _owner.DesignMode) { 143 return; 144 } 145 146 // VSWhidbey 497632. Ignore if uniqueID is empty since the postback won't be valid anyway. 147 if (String.IsNullOrEmpty(uniqueId)) { 148 return; 149 } 150 151 if ((_owner.ControlState < ControlState.PreRendered) && (!_owner.IsCallback)) { 152 throw new InvalidOperationException( 153 SR.GetString(SR.ClientScriptManager_RegisterForEventValidation_Too_Early)); 154 } 155 156 // Step 2: Add this tuple to the list 157 EventValidationProvider.RegisterForEventValidation(uniqueId, argument); 158 159 // Step 3: If there are any partial caching controls on the stack, forward the call to them 160 if (_owner.PartialCachingControlStack != null) { 161 foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) { 162 c.RegisterForEventValidation(uniqueId, argument); 163 } 164 } 165 } 166 SaveEventValidationField()167 internal void SaveEventValidationField() { 168 string fieldValue = GetEventValidationFieldValue(); 169 if (!String.IsNullOrEmpty(fieldValue)) { 170 RegisterHiddenField(Page.EventValidationPrefixID, fieldValue); 171 } 172 } 173 174 // Used by unobtrusive javascript validators to verify that a scriptresource mapping for jquery is registered EnsureJqueryRegistered()175 internal static void EnsureJqueryRegistered() { 176 if (_scriptResourceMapping != null) { 177 if (_scriptResourceMapping.GetDefinition("jquery", typeof(Page).Assembly) == null && 178 _scriptResourceMapping.GetDefinition("jquery") == null) { 179 throw new InvalidOperationException(SR.GetString(SR.ClientScriptManager_JqueryNotRegistered)); 180 } 181 } 182 } 183 EnsureEventValidationFieldLoaded()184 private void EnsureEventValidationFieldLoaded() { 185 if (_eventValidationFieldLoaded) { 186 return; 187 } 188 189 _eventValidationFieldLoaded = true; 190 191 // Step 1: Read the event validation field 192 string unsafeField = null; 193 if (_owner.RequestValueCollection != null) { 194 unsafeField = _owner.RequestValueCollection[Page.EventValidationPrefixID]; 195 } 196 197 if (String.IsNullOrEmpty(unsafeField)) { 198 return; 199 } 200 201 // Step 2: Decrypt the event validation field 202 IStateFormatter2 formatter = _owner.CreateStateFormatter(); 203 object eventValidationField = null; 204 try { 205 eventValidationField = formatter.Deserialize(unsafeField, Purpose.WebForms_ClientScriptManager_EventValidation); 206 } 207 catch (Exception ex) { 208 // DevDiv #461378: Ignore validation errors for cross-page postbacks. Since the ValidateEvent method 209 // is most likely on the call stack right now, this will result in an event validation failure rather 210 // than a MAC validation failure. 211 if (!_owner.ShouldSuppressMacValidationException(ex)) { 212 ViewStateException.ThrowViewStateError(ex, unsafeField); 213 } 214 } 215 216 // Step 3: Load the event validation field into the appropriate provider 217 if (!EventValidationProvider.TryLoadEventValidationField(eventValidationField)) { 218 // Something went wrong while loading the incoming event validation object; the 219 // most likely cause is that it wasn't submitted with the correct ViewState. 220 ViewStateException.ThrowViewStateError(null, unsafeField); 221 } 222 } 223 ValidateEvent(string uniqueId)224 public void ValidateEvent(string uniqueId) { 225 ValidateEvent(uniqueId, String.Empty); 226 } 227 ValidateEvent(string uniqueId, string argument)228 public void ValidateEvent(string uniqueId, string argument) { 229 if (!_owner.EnableEventValidation) { 230 return; 231 } 232 233 if (String.IsNullOrEmpty(uniqueId)) { 234 throw new ArgumentException(SR.GetString(SR.Parameter_NullOrEmpty, "uniqueId"), "uniqueId"); 235 } 236 237 EnsureEventValidationFieldLoaded(); 238 239 // Go against the _eventValidationProvider field instead of the EventValidationProvider 240 // property to avoid the lazy instantiation code if not necessary. 241 if (_eventValidationProvider == null || !_eventValidationProvider.IsValid(uniqueId, argument)) { 242 throw new ArgumentException(SR.GetString(SR.ClientScriptManager_InvalidPostBackArgument)); 243 } 244 } 245 ClearHiddenFields()246 internal void ClearHiddenFields() { 247 _registeredHiddenFields = null; 248 } 249 CreateScriptKey(Type type, string key)250 internal static ScriptKey CreateScriptKey(Type type, string key) { 251 return new ScriptKey(type, key); 252 } 253 CreateScriptIncludeKey(Type type, string key, bool isResource)254 internal static ScriptKey CreateScriptIncludeKey(Type type, string key, bool isResource) { 255 return new ScriptKey(type, key, true, isResource); 256 } 257 258 /// <devdoc> 259 /// Enables controls to obtain client-side script function that will cause 260 /// (when invoked) an out-of-band callback to the server 261 /// </devdoc> GetCallbackEventReference(Control control, string argument, string clientCallback, string context)262 public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context) { 263 return GetCallbackEventReference(control, argument, clientCallback, context, false); 264 } 265 GetCallbackEventReference(Control control, string argument, string clientCallback, string context, bool useAsync)266 public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context, bool useAsync) { 267 return GetCallbackEventReference(control, argument, clientCallback, context, null, useAsync); 268 } 269 270 /// <devdoc> 271 /// Enables controls to obtain client-side script function that will cause 272 /// (when invoked) an out-of-band callback to the server and allows the user to specify a client-side error callback 273 /// </devdoc> GetCallbackEventReference(Control control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)274 public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync) { 275 if (control == null) { 276 throw new ArgumentNullException("control"); 277 } 278 if (!(control is ICallbackEventHandler)) { 279 throw new InvalidOperationException(SR.GetString(SR.Page_CallBackTargetInvalid, control.UniqueID)); 280 } 281 return GetCallbackEventReference("'" + control.UniqueID + "'", argument, clientCallback, context, clientErrorCallback, useAsync); 282 } 283 284 /// <devdoc> 285 /// Enables controls to obtain client-side script function that will cause 286 /// (when invoked) an out-of-band callback to the server and allows the user to specify a client-side error callback 287 /// </devdoc> GetCallbackEventReference(string target, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)288 public string GetCallbackEventReference(string target, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync) { 289 _owner.RegisterWebFormsScript(); 290 if (_owner.ClientSupportsJavaScript && (_owner.RequestInternal != null) && _owner.RequestInternal.Browser.SupportsCallback) { 291 RegisterStartupScript(typeof(Page), PageCallbackScriptKey, (((_owner.RequestInternal != null) && 292 (String.Equals(_owner.RequestInternal.Url.Scheme, "https", StringComparison.OrdinalIgnoreCase))) ? 293 @" 294 var callBackFrameUrl='" + Util.QuoteJScriptString(GetWebResourceUrl(typeof(Page), "SmartNav.htm"), false) + @"'; 295 WebForm_InitCallback();" : 296 @" 297 WebForm_InitCallback();"), true); 298 } 299 if (argument == null) { 300 argument = "null"; 301 } 302 else if (argument.Length == 0) { 303 argument = "\"\""; 304 } 305 if (context == null) { 306 context = "null"; 307 } 308 else if (context.Length == 0) { 309 context = "\"\""; 310 } 311 return _callbackFunctionName + 312 "(" + 313 target + 314 "," + 315 argument + 316 "," + 317 clientCallback + 318 "," + 319 context + 320 "," + 321 ((clientErrorCallback == null) ? "null" : clientErrorCallback) + 322 "," + 323 (useAsync ? "true" : "false") + 324 ")"; 325 } 326 GetPostBackClientHyperlink(Control control, string argument)327 public string GetPostBackClientHyperlink(Control control, string argument) { 328 // We're using escapePercent=true here and false in Page 329 // because true in Page would be a breaking change: 330 // People may already be encoding percent characters before calling this, 331 // and we may double encode it. 332 // Our own classes and new code should almost always use the override with escapePercent=true. 333 return GetPostBackClientHyperlink(control, argument, true, false); 334 } 335 GetPostBackClientHyperlink(Control control, string argument, bool registerForEventValidation)336 public string GetPostBackClientHyperlink(Control control, string argument, bool registerForEventValidation) { 337 // We're using escapePercent=true here and false in Page 338 // because true in Page would be a breaking change: 339 // People may already be encoding percent characters before calling this, 340 // and we may double encode it. 341 // Our own classes and new code should almost always use the override with escapePercent=true. 342 return GetPostBackClientHyperlink(control, argument, true, registerForEventValidation); 343 } 344 345 /// <devdoc> 346 /// <para>This returs a string that can be put in client event to post back to the named control</para> 347 /// </devdoc> GetPostBackClientHyperlink(Control control, string argument, bool escapePercent, bool registerForEventValidation)348 internal string GetPostBackClientHyperlink(Control control, string argument, bool escapePercent, bool registerForEventValidation) { 349 // Hyperlinks always need the language prefix 350 // If used in a hyperlink, the event argument needs to be escaped for % characters 351 // which will otherwise be interpreted as escape sequences (VSWhidbey 421874) 352 return JscriptPrefix + GetPostBackEventReference(control, argument, escapePercent, registerForEventValidation); 353 } 354 GetPostBackEventReference(Control control, string argument)355 public string GetPostBackEventReference(Control control, string argument) { 356 return GetPostBackEventReference(control, argument, false, false); 357 } 358 GetPostBackEventReference(Control control, string argument, bool registerForEventValidation)359 public string GetPostBackEventReference(Control control, string argument, bool registerForEventValidation) { 360 return GetPostBackEventReference(control, argument, false, registerForEventValidation); 361 } 362 363 /* 364 * Enables controls to obtain client-side script function that will cause 365 * (when invoked) a server post-back to the form. 366 * argument: Parameter that will be passed to control on server 367 */ 368 /// <devdoc> 369 /// <para>Passes a parameter to the control that will do the postback processing on the 370 /// server.</para> 371 /// </devdoc> GetPostBackEventReference(Control control, string argument, bool forUrl, bool registerForEventValidation)372 private string GetPostBackEventReference(Control control, string argument, bool forUrl, bool registerForEventValidation) { 373 if (control == null) { 374 throw new ArgumentNullException("control"); 375 } 376 377 _owner.RegisterPostBackScript(); 378 379 string controlID = control.UniqueID; 380 381 if (registerForEventValidation) { 382 RegisterForEventValidation(controlID, argument); 383 } 384 385 // VSWhidbey 475945 386 if (control.EnableLegacyRendering && _owner.IsInOnFormRender && 387 controlID != null && controlID.IndexOf(Control.LEGACY_ID_SEPARATOR) >= 0) { 388 389 controlID = controlID.Replace(Control.LEGACY_ID_SEPARATOR, Control.ID_SEPARATOR); 390 } 391 392 // Split into 2 calls to String.Concat to improve performance. 393 // CLR is investigating whether this should be fixed at a lower level. 394 string postBackEventReference = _postBackFunctionName + "('" + controlID + "','"; 395 // The argument needs to be quoted, in case in contains characters that 396 // can't be used in JScript strings (ASURT 71818). 397 postBackEventReference += Util.QuoteJScriptString(argument, forUrl) + "')"; 398 399 return postBackEventReference; 400 } 401 402 /// <devdoc> 403 /// <para>Passes a parameter to the control that will do the postback processing on the 404 /// server.</para> 405 /// </devdoc> GetPostBackEventReference(PostBackOptions options)406 public string GetPostBackEventReference(PostBackOptions options) { 407 return GetPostBackEventReference(options, false); 408 } 409 GetPostBackEventReference(PostBackOptions options, bool registerForEventValidation)410 public string GetPostBackEventReference(PostBackOptions options, bool registerForEventValidation) { 411 if (options == null) { 412 throw new ArgumentNullException("options"); 413 } 414 415 if (registerForEventValidation) { 416 RegisterForEventValidation(options); 417 } 418 419 StringBuilder builder = new StringBuilder(); 420 bool shouldRenderPostBackReferenceString = false; 421 422 if (options.RequiresJavaScriptProtocol) { 423 builder.Append(JscriptPrefix); 424 } 425 426 if (options.AutoPostBack) { 427 builder.Append("setTimeout('"); 428 } 429 430 // Use the old __doPostBack method if not using other postback features. 431 if (!options.PerformValidation && !options.TrackFocus && options.ClientSubmit && 432 string.IsNullOrEmpty(options.ActionUrl)) { 433 string postbackRef = GetPostBackEventReference(options.TargetControl, options.Argument); 434 435 // Need to quote the string if auto posting back 436 if (options.AutoPostBack) { 437 builder.Append(Util.QuoteJScriptString(postbackRef)); 438 builder.Append("', 0)"); 439 } 440 else { 441 builder.Append(postbackRef); 442 } 443 444 return builder.ToString(); 445 } 446 447 builder.Append(_postbackOptionsFunctionName); 448 builder.Append("(new WebForm_PostBackOptions(\""); 449 builder.Append(options.TargetControl.UniqueID); 450 builder.Append("\", "); 451 452 if (String.IsNullOrEmpty(options.Argument)) { 453 builder.Append("\"\", "); 454 } 455 else { 456 builder.Append("\""); 457 builder.Append(Util.QuoteJScriptString(options.Argument)); 458 builder.Append("\", "); 459 } 460 461 if (options.PerformValidation) { 462 shouldRenderPostBackReferenceString = true; 463 builder.Append("true, "); 464 } 465 else { 466 builder.Append("false, "); 467 } 468 469 if (options.ValidationGroup != null && options.ValidationGroup.Length > 0) { 470 shouldRenderPostBackReferenceString = true; 471 472 builder.Append("\""); 473 builder.Append(options.ValidationGroup); 474 builder.Append("\", "); 475 } 476 else { 477 builder.Append("\"\", "); 478 } 479 480 if (options.ActionUrl != null && options.ActionUrl.Length > 0) { 481 shouldRenderPostBackReferenceString = true; 482 _owner.ContainsCrossPagePost = true; 483 484 builder.Append("\""); 485 builder.Append(Util.QuoteJScriptString(options.ActionUrl)); 486 builder.Append("\", "); 487 } 488 else { 489 builder.Append("\"\", "); 490 } 491 492 if (options.TrackFocus) { 493 _owner.RegisterFocusScript(); 494 shouldRenderPostBackReferenceString = true; 495 builder.Append("true, "); 496 } 497 else { 498 builder.Append("false, "); 499 } 500 501 if (options.ClientSubmit) { 502 shouldRenderPostBackReferenceString = true; 503 _owner.RegisterPostBackScript(); 504 505 builder.Append("true))"); 506 } 507 else { 508 builder.Append("false))"); 509 } 510 511 if (options.AutoPostBack) { 512 builder.Append("', 0)"); 513 } 514 515 string reference = null; 516 if (shouldRenderPostBackReferenceString) { 517 reference = builder.ToString(); 518 _owner.RegisterWebFormsScript(); 519 } 520 521 return reference; 522 } 523 524 /// <devdoc> 525 /// Gets a URL resource reference to a client-side resource 526 /// </devdoc> GetWebResourceUrl(Type type, string resourceName)527 public string GetWebResourceUrl(Type type, string resourceName) { 528 return GetWebResourceUrl(_owner, type, resourceName, false, 529 (_owner == null ? null : _owner.ScriptManager)); 530 } 531 GetWebResourceUrl(Page owner, Type type, string resourceName, bool htmlEncoded, IScriptManager scriptManager)532 internal static string GetWebResourceUrl(Page owner, Type type, string resourceName, bool htmlEncoded, IScriptManager scriptManager) { 533 bool enableCdn = scriptManager != null && scriptManager.EnableCdn; 534 return GetWebResourceUrl(owner, type, resourceName, htmlEncoded, scriptManager, enableCdn); 535 } 536 GetWebResourceUrl(Page owner, Type type, string resourceName, bool htmlEncoded, IScriptManager scriptManager, bool enableCdn)537 internal static string GetWebResourceUrl(Page owner, Type type, string resourceName, bool htmlEncoded, IScriptManager scriptManager, bool enableCdn) { 538 if (type == null) { 539 throw new ArgumentNullException("type"); 540 } 541 542 if (String.IsNullOrEmpty(resourceName)) { 543 throw new ArgumentNullException("resourceName"); 544 } 545 546 if (owner != null && owner.DesignMode) { 547 ISite site = ((IComponent)owner).Site; 548 if (site != null) { 549 IResourceUrlGenerator urlGenerator = site.GetService(typeof(IResourceUrlGenerator)) as IResourceUrlGenerator; 550 if (urlGenerator != null) { 551 return urlGenerator.GetResourceUrl(type, resourceName); 552 } 553 } 554 555 return resourceName; 556 } 557 else { 558 return AssemblyResourceLoader.GetWebResourceUrl(type, resourceName, htmlEncoded, scriptManager, enableCdn: enableCdn); 559 } 560 } 561 562 /// <devdoc> 563 /// <para>Determines if the client script block is registered with the page.</para> 564 /// </devdoc> IsClientScriptBlockRegistered(string key)565 public bool IsClientScriptBlockRegistered(string key) { 566 return IsClientScriptBlockRegistered(typeof(Page), key); 567 } 568 569 /// <devdoc> 570 /// <para>Determines if the client script block is registered with the page.</para> 571 /// </devdoc> IsClientScriptBlockRegistered(Type type, string key)572 public bool IsClientScriptBlockRegistered(Type type, string key) { 573 if (type == null) { 574 throw new ArgumentNullException("type"); 575 } 576 577 return (_registeredClientScriptBlocks != null 578 && (_registeredClientScriptBlocks.Contains(CreateScriptKey(type, key)))); 579 } 580 581 /// <devdoc> 582 /// <para>Determines if the onsubmit script is registered with the page.</para> 583 /// </devdoc> IsClientScriptIncludeRegistered(string key)584 public bool IsClientScriptIncludeRegistered(string key) { 585 return IsClientScriptIncludeRegistered(typeof(Page), key); 586 } 587 588 /// <devdoc> 589 /// <para>Determines if the onsubmit script is registered with the page.</para> 590 /// </devdoc> IsClientScriptIncludeRegistered(Type type, string key)591 public bool IsClientScriptIncludeRegistered(Type type, string key) { 592 if (type == null) { 593 throw new ArgumentNullException("type"); 594 } 595 596 return (_registeredClientScriptBlocks != null 597 && (_registeredClientScriptBlocks.Contains(CreateScriptIncludeKey(type, key, false)))); 598 } 599 600 /// <devdoc> 601 /// <para>Determines if the client startup script is registered with the 602 /// page.</para> 603 /// </devdoc> IsStartupScriptRegistered(string key)604 public bool IsStartupScriptRegistered(string key) { 605 return IsStartupScriptRegistered(typeof(Page), key); 606 } 607 608 /// <devdoc> 609 /// <para>Determines if the client startup script is registered with the 610 /// page.</para> 611 /// </devdoc> IsStartupScriptRegistered(Type type, string key)612 public bool IsStartupScriptRegistered(Type type, string key) { 613 if (type == null) { 614 throw new ArgumentNullException("type"); 615 } 616 617 return (_registeredClientStartupScripts != null 618 && (_registeredClientStartupScripts.Contains(CreateScriptKey(type, key)))); 619 } 620 621 /// <devdoc> 622 /// <para>Determines if the onsubmit script is registered with the page.</para> 623 /// </devdoc> IsOnSubmitStatementRegistered(string key)624 public bool IsOnSubmitStatementRegistered(string key) { 625 return IsOnSubmitStatementRegistered(typeof(Page), key); 626 } 627 628 /// <devdoc> 629 /// <para>Determines if the onsubmit script is registered with the page.</para> 630 /// </devdoc> IsOnSubmitStatementRegistered(Type type, string key)631 public bool IsOnSubmitStatementRegistered(Type type, string key) { 632 if (type == null) { 633 throw new ArgumentNullException("type"); 634 } 635 636 return (_registeredOnSubmitStatements != null 637 && (_registeredOnSubmitStatements.Contains(CreateScriptKey(type, key)))); 638 } 639 640 /// <devdoc> 641 /// <para>Declares a value that will be declared as a JavaScript array declaration 642 /// when the page renders. This can be used by script-based controls to declare 643 /// themselves within an array so that a client script library can work with 644 /// all the controls of the same type.</para> 645 /// </devdoc> RegisterArrayDeclaration(string arrayName, string arrayValue)646 public void RegisterArrayDeclaration(string arrayName, string arrayValue) { 647 if (arrayName == null) { 648 throw new ArgumentNullException("arrayName"); 649 } 650 if (_registeredArrayDeclares == null) { 651 _registeredArrayDeclares = new ListDictionary(); 652 } 653 if (!_registeredArrayDeclares.Contains(arrayName)) { 654 _registeredArrayDeclares[arrayName] = new ArrayList(); 655 } 656 657 ArrayList elements = (ArrayList)_registeredArrayDeclares[arrayName]; 658 elements.Add(arrayValue); 659 660 // If there are any partial caching controls on the stack, forward the call to them 661 if (_owner.PartialCachingControlStack != null) { 662 foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) { 663 c.RegisterArrayDeclaration(arrayName, arrayValue); 664 } 665 } 666 } 667 668 // RegisterArrayDeclaration implementation that supports partial rendering. RegisterArrayDeclaration(Control control, string arrayName, string arrayValue)669 internal void RegisterArrayDeclaration(Control control, string arrayName, string arrayValue) { 670 IScriptManager scriptManager = _owner.ScriptManager; 671 if ((scriptManager != null) && scriptManager.SupportsPartialRendering) { 672 scriptManager.RegisterArrayDeclaration(control, arrayName, arrayValue); 673 } 674 else { 675 RegisterArrayDeclaration(arrayName, arrayValue); 676 } 677 } 678 RegisterExpandoAttribute(string controlId, string attributeName, string attributeValue)679 public void RegisterExpandoAttribute(string controlId, string attributeName, string attributeValue) { 680 RegisterExpandoAttribute(controlId, attributeName, attributeValue, true); 681 } 682 RegisterExpandoAttribute(string controlId, string attributeName, string attributeValue, bool encode)683 public void RegisterExpandoAttribute(string controlId, string attributeName, string attributeValue, bool encode) { 684 // check paramters 685 WebUtil.StringUtil.CheckAndTrimString(controlId, "controlId"); 686 WebUtil.StringUtil.CheckAndTrimString(attributeName, "attributeName"); 687 688 ListDictionary expandoAttributes = null; 689 if (_registeredControlsWithExpandoAttributes == null) { 690 _registeredControlsWithExpandoAttributes = new ListDictionary(StringComparer.Ordinal); 691 } 692 else { 693 expandoAttributes = (ListDictionary)_registeredControlsWithExpandoAttributes[controlId]; 694 } 695 696 if (expandoAttributes == null) { 697 expandoAttributes = new ListDictionary(StringComparer.Ordinal); 698 _registeredControlsWithExpandoAttributes.Add(controlId, expandoAttributes); 699 } 700 701 if (encode) { 702 attributeValue = Util.QuoteJScriptString(attributeValue); 703 } 704 705 expandoAttributes.Add(attributeName, attributeValue); 706 707 // If there are any partial caching controls on the stack, forward the call to them 708 if (_owner.PartialCachingControlStack != null) { 709 foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) { 710 c.RegisterExpandoAttribute(controlId, attributeName, attributeValue); 711 } 712 } 713 } 714 715 // RegisterExpandoAttribute implementation that supports partial rendering. RegisterExpandoAttribute(Control control, string controlId, string attributeName, string attributeValue, bool encode)716 internal void RegisterExpandoAttribute(Control control, string controlId, string attributeName, string attributeValue, bool encode) { 717 IScriptManager scriptManager = _owner.ScriptManager; 718 if ((scriptManager != null) && scriptManager.SupportsPartialRendering) { 719 scriptManager.RegisterExpandoAttribute(control, controlId, attributeName, attributeValue, encode); 720 } 721 else { 722 RegisterExpandoAttribute(controlId, attributeName, attributeValue, encode); 723 } 724 } 725 726 /// <devdoc> 727 /// <para> 728 /// Allows controls to automatically register a hidden field on the form. The 729 /// field will be emitted when the form control renders itself. 730 /// </para> 731 /// </devdoc> RegisterHiddenField(string hiddenFieldName, string hiddenFieldInitialValue)732 public void RegisterHiddenField(string hiddenFieldName, 733 string hiddenFieldInitialValue) { 734 if (hiddenFieldName == null) { 735 throw new ArgumentNullException("hiddenFieldName"); 736 } 737 if (_registeredHiddenFields == null) 738 _registeredHiddenFields = new ListDictionary(); 739 740 if (!_registeredHiddenFields.Contains(hiddenFieldName)) 741 _registeredHiddenFields.Add(hiddenFieldName, hiddenFieldInitialValue); 742 if (_owner._hiddenFieldsToRender == null) { 743 _owner._hiddenFieldsToRender = new Dictionary<String, String>(); 744 } 745 _owner._hiddenFieldsToRender[hiddenFieldName] = hiddenFieldInitialValue; 746 747 // If there are any partial caching controls on the stack, forward the call to them 748 if (_owner.PartialCachingControlStack != null) { 749 foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) { 750 c.RegisterHiddenField(hiddenFieldName, hiddenFieldInitialValue); 751 } 752 } 753 } 754 755 // RegisterHiddenField implementation that supports partial rendering. RegisterHiddenField(Control control, string hiddenFieldName, string hiddenFieldValue)756 internal void RegisterHiddenField(Control control, string hiddenFieldName, string hiddenFieldValue) { 757 IScriptManager scriptManager = _owner.ScriptManager; 758 if ((scriptManager != null) && scriptManager.SupportsPartialRendering) { 759 scriptManager.RegisterHiddenField(control, hiddenFieldName, hiddenFieldValue); 760 } 761 else { 762 RegisterHiddenField(hiddenFieldName, hiddenFieldValue); 763 } 764 } 765 766 767 /// <devdoc> 768 /// Prevents controls from sending duplicate blocks of 769 /// client-side script to the client. Any script blocks with the same type and key 770 /// values are considered duplicates.</para> 771 /// </devdoc> RegisterClientScriptBlock(Type type, string key, string script)772 public void RegisterClientScriptBlock(Type type, string key, string script) { 773 RegisterClientScriptBlock(type, key, script, false); 774 } 775 776 /// <devdoc> 777 /// Prevents controls from sending duplicate blocks of 778 /// client-side script to the client. Any script blocks with the same type and key 779 /// values are considered duplicates.</para> 780 /// </devdoc> RegisterClientScriptBlock(Type type, string key, string script, bool addScriptTags)781 public void RegisterClientScriptBlock(Type type, string key, string script, bool addScriptTags) { 782 if (type == null) { 783 throw new ArgumentNullException("type"); 784 } 785 786 if (addScriptTags) { 787 RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientScriptBlocksWithoutTags); 788 } 789 else { 790 RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientScriptBlocks); 791 } 792 } 793 794 // RegisterClientScriptBlock implementation that supports partial rendering. RegisterClientScriptBlock(Control control, Type type, string key, string script, bool addScriptTags)795 internal void RegisterClientScriptBlock(Control control, Type type, string key, string script, bool addScriptTags) { 796 IScriptManager scriptManager = _owner.ScriptManager; 797 if ((scriptManager != null) && scriptManager.SupportsPartialRendering) { 798 scriptManager.RegisterClientScriptBlock(control, type, key, script, addScriptTags); 799 } 800 else { 801 RegisterClientScriptBlock(type, key, script, addScriptTags); 802 } 803 } 804 805 806 /// <devdoc> 807 /// <para> Prevents controls from sending duplicate blocks of 808 /// client-side script to the client. Any script blocks with the same <paramref name="key"/> parameter 809 /// values are considered duplicates.</para> 810 /// </devdoc> RegisterClientScriptInclude(string key, string url)811 public void RegisterClientScriptInclude(string key, string url) { 812 RegisterClientScriptInclude(typeof(Page), key, url); 813 } 814 815 /// <devdoc> 816 /// Prevents controls from sending duplicate blocks of 817 /// client-side script to the client. Any script blocks with the same type and key 818 /// values are considered duplicates.</para> 819 /// </devdoc> RegisterClientScriptInclude(Type type, string key, string url)820 public void RegisterClientScriptInclude(Type type, string key, string url) { 821 RegisterClientScriptInclude(type, key, url, false); 822 } 823 RegisterClientScriptInclude(Type type, string key, string url, bool isResource)824 internal void RegisterClientScriptInclude(Type type, string key, string url, bool isResource) { 825 if (type == null) { 826 throw new ArgumentNullException("type"); 827 } 828 if (String.IsNullOrEmpty(url)) { 829 throw ExceptionUtil.ParameterNullOrEmpty("url"); 830 } 831 832 // VSWhidbey 499036: encode the url 833 string script = IncludeScriptBegin + HttpUtility.HtmlAttributeEncode(url) + IncludeScriptEnd; 834 RegisterScriptBlock(CreateScriptIncludeKey(type, key, isResource), script, ClientAPIRegisterType.ClientScriptBlocks); 835 } 836 837 // RegisterClientScriptInclude implementation that supports partial rendering. RegisterClientScriptInclude(Control control, Type type, string key, string url)838 internal void RegisterClientScriptInclude(Control control, Type type, string key, string url) { 839 IScriptManager scriptManager = _owner.ScriptManager; 840 if ((scriptManager != null) && scriptManager.SupportsPartialRendering) { 841 scriptManager.RegisterClientScriptInclude(control, type, key, url); 842 } 843 else { 844 RegisterClientScriptInclude(type, key, url); 845 } 846 } 847 848 849 /// <devdoc> 850 /// </devdoc> RegisterClientScriptResource(Type type, string resourceName)851 public void RegisterClientScriptResource(Type type, string resourceName) { 852 if (type == null) { 853 throw new ArgumentNullException("type"); 854 } 855 856 RegisterClientScriptInclude(type, resourceName, GetWebResourceUrl(type, resourceName), true); 857 } 858 859 // RegisterClientScriptResource implementation that supports partial rendering. RegisterClientScriptResource(Control control, Type type, string resourceName)860 internal void RegisterClientScriptResource(Control control, Type type, string resourceName) { 861 IScriptManager scriptManager = _owner.ScriptManager; 862 if ((scriptManager != null) && scriptManager.SupportsPartialRendering) { 863 scriptManager.RegisterClientScriptResource(control, type, resourceName); 864 } 865 else { 866 RegisterClientScriptResource(type, resourceName); 867 } 868 } 869 870 RegisterDefaultButtonScript(Control button, HtmlTextWriter writer, bool useAddAttribute)871 internal void RegisterDefaultButtonScript(Control button, HtmlTextWriter writer, bool useAddAttribute) { 872 _owner.RegisterWebFormsScript(); 873 if (_owner.EnableLegacyRendering) { 874 if (useAddAttribute) { 875 writer.AddAttribute("language", "javascript", false); 876 } 877 else { 878 writer.WriteAttribute("language", "javascript", false); 879 } 880 } 881 string keyPress = "javascript:return WebForm_FireDefaultButton(event, '" + button.ClientID + "')"; 882 if (useAddAttribute) { 883 writer.AddAttribute("onkeypress", keyPress); 884 } 885 else { 886 writer.WriteAttribute("onkeypress", keyPress); 887 } 888 } 889 890 /// <devdoc> 891 /// <para>Allows a control to access a the client 892 /// <see langword='onsubmit'/> event. 893 /// The script should be a function call to client code registered elsewhere.</para> 894 /// </devdoc> RegisterOnSubmitStatement(Type type, string key, string script)895 public void RegisterOnSubmitStatement(Type type, string key, string script) { 896 if (type == null) { 897 throw new ArgumentNullException("type"); 898 } 899 900 RegisterOnSubmitStatementInternal(CreateScriptKey(type, key), script); 901 } 902 903 904 // RegisterOnSubmitStatement implementation that supports partial rendering. RegisterOnSubmitStatement(Control control, Type type, string key, string script)905 internal void RegisterOnSubmitStatement(Control control, Type type, string key, string script) { 906 IScriptManager scriptManager = _owner.ScriptManager; 907 if ((scriptManager != null) && scriptManager.SupportsPartialRendering) { 908 scriptManager.RegisterOnSubmitStatement(control, type, key, script); 909 } 910 else { 911 RegisterOnSubmitStatement(type, key, script); 912 } 913 } 914 915 RegisterOnSubmitStatementInternal(ScriptKey key, string script)916 internal void RegisterOnSubmitStatementInternal(ScriptKey key, string script) { 917 if (String.IsNullOrEmpty(script)) { 918 throw ExceptionUtil.ParameterNullOrEmpty("script"); 919 } 920 if (_registeredOnSubmitStatements == null) 921 _registeredOnSubmitStatements = new ListDictionary(); 922 923 // Make sure the script block ends in a semicolon 924 int index = script.Length - 1; 925 while ((index >= 0) && Char.IsWhiteSpace(script, index)) { 926 index--; 927 } 928 929 if ((index >= 0) && (script[index] != ';')) { 930 script = script.Substring(0, index + 1) + ";" + script.Substring(index + 1); 931 } 932 933 if (!_registeredOnSubmitStatements.Contains(key)) 934 _registeredOnSubmitStatements.Add(key, script); 935 936 // If there are any partial caching controls on the stack, forward the call to them 937 if (_owner.PartialCachingControlStack != null) { 938 foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) { 939 c.RegisterOnSubmitStatement(key, script); 940 } 941 } 942 } 943 RegisterScriptBlock(ScriptKey key, string script, ClientAPIRegisterType type)944 internal void RegisterScriptBlock(ScriptKey key, string script, ClientAPIRegisterType type) { 945 946 // Call RegisterScriptBlock with the correct collection based on the blockType 947 switch (type) { 948 case ClientAPIRegisterType.ClientScriptBlocks: 949 RegisterScriptBlock(key, script, ref _registeredClientScriptBlocks, ref _clientScriptBlocks, false); 950 break; 951 case ClientAPIRegisterType.ClientScriptBlocksWithoutTags: 952 RegisterScriptBlock(key, script, ref _registeredClientScriptBlocks, ref _clientScriptBlocks, true); 953 break; 954 case ClientAPIRegisterType.ClientStartupScripts: 955 RegisterScriptBlock(key, script, ref _registeredClientStartupScripts, ref _clientStartupScripts, false); 956 break; 957 case ClientAPIRegisterType.ClientStartupScriptsWithoutTags: 958 RegisterScriptBlock(key, script, ref _registeredClientStartupScripts, ref _clientStartupScripts, true); 959 break; 960 default: 961 Debug.Assert(false); 962 break; 963 } 964 965 // If there are any partial caching controls on the stack, forward the call to them 966 if (_owner.PartialCachingControlStack != null) { 967 foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) { 968 c.RegisterScriptBlock(type, key, script); 969 } 970 } 971 } 972 RegisterScriptBlock(ScriptKey key, string script, ref ListDictionary scriptBlocks, ref ArrayList scriptList, bool needsScriptTags)973 private void RegisterScriptBlock(ScriptKey key, string script, ref ListDictionary scriptBlocks, ref ArrayList scriptList, bool needsScriptTags) { 974 if (scriptBlocks == null) { 975 scriptBlocks = new ListDictionary(); 976 scriptList = new ArrayList(); 977 } 978 979 if (!scriptBlocks.Contains(key)) { 980 Tuple<ScriptKey, String, Boolean> entry = new Tuple<ScriptKey, String, Boolean>(key, script, needsScriptTags); 981 scriptBlocks.Add(key, null); 982 scriptList.Add(entry); 983 } 984 } 985 986 /// <devdoc> 987 /// <para> 988 /// Allows controls to keep duplicate blocks of client-side script code from 989 /// being sent to the client. Any script blocks with the same type and key 990 /// value are considered duplicates. 991 /// </para> 992 /// </devdoc> RegisterStartupScript(Type type, string key, string script)993 public void RegisterStartupScript(Type type, string key, string script) { 994 RegisterStartupScript(type, key, script, false); 995 } 996 997 /// <devdoc> 998 /// <para> 999 /// Allows controls to keep duplicate blocks of client-side script code from 1000 /// being sent to the client. Any script blocks with the same type and key 1001 /// value are considered duplicates. 1002 /// </para> 1003 /// </devdoc> RegisterStartupScript(Type type, string key, string script, bool addScriptTags)1004 public void RegisterStartupScript(Type type, string key, string script, bool addScriptTags) { 1005 if (type == null) { 1006 throw new ArgumentNullException("type"); 1007 } 1008 1009 if (addScriptTags) { 1010 RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientStartupScriptsWithoutTags); 1011 } 1012 else { 1013 RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientStartupScripts); 1014 } 1015 } 1016 1017 // RegisterStartupScript implementation that supports partial rendering. RegisterStartupScript(Control control, Type type, string key, string script, bool addScriptTags)1018 internal void RegisterStartupScript(Control control, Type type, string key, string script, bool addScriptTags) { 1019 IScriptManager scriptManager = _owner.ScriptManager; 1020 if ((scriptManager != null) && scriptManager.SupportsPartialRendering) { 1021 scriptManager.RegisterStartupScript(control, type, key, script, addScriptTags); 1022 } 1023 else { 1024 RegisterStartupScript(type, key, script, addScriptTags); 1025 } 1026 } 1027 1028 RenderArrayDeclares(HtmlTextWriter writer)1029 internal void RenderArrayDeclares(HtmlTextWriter writer) { 1030 if (_registeredArrayDeclares == null || _registeredArrayDeclares.Count == 0) { 1031 return; 1032 } 1033 1034 writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart); 1035 1036 // Write out each array 1037 IDictionaryEnumerator arrays = _registeredArrayDeclares.GetEnumerator(); 1038 while (arrays.MoveNext()) { 1039 // Write the declaration 1040 writer.Write("var "); 1041 writer.Write(arrays.Key); 1042 writer.Write(" = new Array("); 1043 1044 // Write each element 1045 IEnumerator elements = ((ArrayList)arrays.Value).GetEnumerator(); 1046 bool first = true; 1047 while (elements.MoveNext()) { 1048 if (first) { 1049 first = false; 1050 } 1051 else { 1052 writer.Write(", "); 1053 } 1054 writer.Write(elements.Current); 1055 } 1056 1057 // Close the declaration 1058 writer.WriteLine(");"); 1059 } 1060 1061 writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd); 1062 } 1063 RenderExpandoAttribute(HtmlTextWriter writer)1064 internal void RenderExpandoAttribute(HtmlTextWriter writer) { 1065 if (_registeredControlsWithExpandoAttributes == null || 1066 _registeredControlsWithExpandoAttributes.Count == 0) { 1067 return; 1068 } 1069 1070 writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart); 1071 1072 foreach (DictionaryEntry controlEntry in _registeredControlsWithExpandoAttributes) { 1073 string controlId = (string)controlEntry.Key; 1074 writer.Write("var "); 1075 writer.Write(controlId); 1076 writer.Write(" = document.all ? document.all[\""); 1077 writer.Write(controlId); 1078 writer.Write("\"] : document.getElementById(\""); 1079 writer.Write(controlId); 1080 writer.WriteLine("\");"); 1081 1082 ListDictionary expandoAttributes = (ListDictionary)controlEntry.Value; 1083 Debug.Assert(expandoAttributes != null && expandoAttributes.Count > 0); 1084 foreach (DictionaryEntry expandoAttribute in expandoAttributes) { 1085 writer.Write(controlId); 1086 writer.Write("."); 1087 writer.Write(expandoAttribute.Key); 1088 if (expandoAttribute.Value == null) { 1089 // VSWhidbey 382151 Render out null string for nulls 1090 writer.WriteLine(" = null;"); 1091 } 1092 else { 1093 writer.Write(" = \""); 1094 writer.Write(expandoAttribute.Value); 1095 writer.WriteLine("\";"); 1096 } 1097 } 1098 } 1099 1100 writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd); 1101 } 1102 RenderHiddenFields(HtmlTextWriter writer)1103 internal void RenderHiddenFields(HtmlTextWriter writer) { 1104 if (_registeredHiddenFields == null || _registeredHiddenFields.Count == 0) { 1105 return; 1106 } 1107 1108 foreach (DictionaryEntry entry in _registeredHiddenFields) { 1109 string entryKey = (string)entry.Key; 1110 if (entryKey == null) { 1111 entryKey = String.Empty; 1112 } 1113 writer.WriteLine(); 1114 writer.Write("<input type=\"hidden\" name=\""); 1115 writer.Write(entryKey); 1116 writer.Write("\" id=\""); 1117 writer.Write(entryKey); 1118 writer.Write("\" value=\""); 1119 HttpUtility.HtmlEncode((string)entry.Value, writer); 1120 writer.Write("\" />"); 1121 } 1122 1123 ClearHiddenFields(); 1124 } 1125 RenderClientScriptBlocks(HtmlTextWriter writer)1126 internal void RenderClientScriptBlocks(HtmlTextWriter writer) { 1127 bool inScriptBlock = false; 1128 if (_clientScriptBlocks != null) { 1129 inScriptBlock = RenderRegisteredScripts(writer, _clientScriptBlocks, true); 1130 } 1131 1132 // Emit the onSubmit function, in necessary 1133 if (!String.IsNullOrEmpty(_owner.ClientOnSubmitEvent) && _owner.ClientSupportsJavaScript) { 1134 // If we were already inside a script tag, don't emit a new open script tag 1135 if (!inScriptBlock) { 1136 writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart); 1137 } 1138 1139 writer.Write(@"function WebForm_OnSubmit() { 1140 "); 1141 if (_registeredOnSubmitStatements != null) { 1142 foreach (string s in _registeredOnSubmitStatements.Values) { 1143 writer.Write(s); 1144 } 1145 } 1146 writer.WriteLine(@" 1147 return true; 1148 }"); 1149 // We always need to close the script tag 1150 writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd); 1151 } 1152 // If there was no onSubmit function, close the script tag if needed 1153 else if (inScriptBlock) { 1154 writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd); 1155 } 1156 } 1157 RenderClientStartupScripts(HtmlTextWriter writer)1158 internal void RenderClientStartupScripts(HtmlTextWriter writer) { 1159 if (_clientStartupScripts != null) { 1160 bool inScriptBlock = RenderRegisteredScripts(writer, _clientStartupScripts, false); 1161 // Close the script tag if needed 1162 if (inScriptBlock) { 1163 writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd); 1164 } 1165 } 1166 } 1167 RenderRegisteredScripts(HtmlTextWriter writer, ArrayList scripts, bool checkForScriptManagerRegistrations)1168 private bool RenderRegisteredScripts(HtmlTextWriter writer, ArrayList scripts, bool checkForScriptManagerRegistrations) { 1169 writer.WriteLine(); 1170 bool inScriptBlock = false; 1171 checkForScriptManagerRegistrations &= (_registeredResourcesToSuppress != null); 1172 // Write out each registered script block 1173 foreach (Tuple<ScriptKey, String, Boolean> entry in scripts) { 1174 if (checkForScriptManagerRegistrations) { 1175 ScriptKey scriptKey = entry.Item1; 1176 if (scriptKey.IsResource) { 1177 Dictionary<String, Object> resources; 1178 if (_registeredResourcesToSuppress.TryGetValue(scriptKey.Assembly, out resources) 1179 && resources.ContainsKey(scriptKey.Key)) { 1180 // this is a suppressed resource 1181 continue; 1182 } 1183 } 1184 } 1185 if (entry.Item3) { 1186 if (!inScriptBlock) { 1187 // If we need script tags and we're not in a script tag, emit a start script tag 1188 writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart); 1189 inScriptBlock = true; 1190 } 1191 } 1192 else if (inScriptBlock) { 1193 // If we don't need script tags, and we're in a script tag, emit an end script tag 1194 writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd); 1195 inScriptBlock = false; 1196 } 1197 writer.Write(entry.Item2); 1198 } 1199 return inScriptBlock; 1200 } 1201 RenderWebFormsScript(HtmlTextWriter writer)1202 internal void RenderWebFormsScript(HtmlTextWriter writer) { 1203 const string webFormScript = "WebForms.js"; 1204 if (_registeredResourcesToSuppress != null) { 1205 Dictionary<String, Object> systemWebResources; 1206 if (_registeredResourcesToSuppress.TryGetValue(AssemblyResourceLoader.GetAssemblyFromType(typeof(Page)), 1207 out systemWebResources) && 1208 systemWebResources.ContainsKey("WebForms.js")) { 1209 return; 1210 } 1211 } 1212 writer.Write(IncludeScriptBegin); 1213 writer.Write(GetWebResourceUrl(_owner, typeof(Page), webFormScript, htmlEncoded: true, scriptManager: _owner.ScriptManager)); 1214 writer.Write(IncludeScriptEnd); 1215 1216 // Render the fallback script for WebForm.js 1217 if (_owner.ScriptManager != null && _owner.ScriptManager.EnableCdn && _owner.ScriptManager.EnableCdnFallback) { 1218 var localPath = GetWebResourceUrl(_owner, typeof(Page), webFormScript, htmlEncoded: true, scriptManager: _owner.ScriptManager, enableCdn: false); 1219 if (!String.IsNullOrEmpty(localPath)) { 1220 writer.Write(ClientScriptStart); 1221 writer.Write(@"window.WebForm_PostBackOptions||document.write('<script type=""text/javascript"" src=""" + localPath + @"""><\/script>');"); 1222 writer.Write(ClientScriptEnd); 1223 } 1224 } 1225 writer.WriteLine(); 1226 } 1227 1228 private interface IEventValidationProvider { 1229 // Gets an object that - when serialized and encrypted - is the outbound __EVENTVALIDATION field value. GetEventValidationStoreObject()1230 object GetEventValidationStoreObject(); 1231 1232 // Returns a value denoting whether this (uniqueId, argument) tuple is valid for the current postback. IsValid(string uniqueId, string argument)1233 bool IsValid(string uniqueId, string argument); 1234 1235 // Registers the tuple (uniqueId, argument) as a valid event for the next postback. RegisterForEventValidation(string uniqueId, string argument)1236 void RegisterForEventValidation(string uniqueId, string argument); 1237 1238 // Given the deserialized form of an incoming __EVENTVALIDATION field, tries to load the valid 1239 // event references for this postback. Returns true on success, false on failure. TryLoadEventValidationField(object eventValidationField)1240 bool TryLoadEventValidationField(object eventValidationField); 1241 } 1242 1243 // provides a more secure implementation of event validation (fix for DevDiv #233564) 1244 private sealed class DefaultEventValidationProvider : IEventValidationProvider { 1245 private readonly ClientScriptManager _clientScriptManager; 1246 private EventValidationStore _inboundEvents; // events which are valid for the current postback 1247 private EventValidationStore _outboundEvents; // events which will be valid on the next postback 1248 DefaultEventValidationProvider(ClientScriptManager clientScriptManager)1249 internal DefaultEventValidationProvider(ClientScriptManager clientScriptManager) { 1250 _clientScriptManager = clientScriptManager; 1251 } 1252 GetEventValidationStoreObject()1253 public object GetEventValidationStoreObject() { 1254 // We only produce the object to be serialized if there is data in the store 1255 if (_outboundEvents != null && _outboundEvents.Count > 0) { 1256 return _outboundEvents; 1257 } 1258 else { 1259 return null; 1260 } 1261 } 1262 IsValid(string uniqueId, string argument)1263 public bool IsValid(string uniqueId, string argument) { 1264 return _inboundEvents != null && _inboundEvents.Contains(uniqueId, argument); 1265 } 1266 RegisterForEventValidation(string uniqueId, string argument)1267 public void RegisterForEventValidation(string uniqueId, string argument) { 1268 if (_outboundEvents == null) { 1269 if (_clientScriptManager._owner.IsCallback) { 1270 _clientScriptManager.EnsureEventValidationFieldLoaded(); 1271 1272 // _outboundEvents could have been initialized by the call to EnsureEventValidationFieldLoaded. 1273 if (_outboundEvents == null) { 1274 _outboundEvents = new EventValidationStore(); 1275 } 1276 } 1277 else { 1278 // Make a new store object and tie it to the outbound __VIEWSTATE field. 1279 // (This is the only field which can have a null/empty 'target'.) 1280 _outboundEvents = new EventValidationStore(); 1281 _outboundEvents.Add(null, _clientScriptManager._owner.ClientState); 1282 } 1283 } 1284 1285 _outboundEvents.Add(uniqueId, argument); 1286 } 1287 TryLoadEventValidationField(object eventValidationField)1288 public bool TryLoadEventValidationField(object eventValidationField) { 1289 EventValidationStore validatedIncomingEvents = eventValidationField as EventValidationStore; 1290 if (validatedIncomingEvents == null || validatedIncomingEvents.Count < 1) { 1291 return true; // empty collection is not an error condition 1292 } 1293 1294 Debug.Assert(_outboundEvents == null); 1295 1296 string viewStateString = _clientScriptManager._owner.RequestViewStateString; 1297 if (!validatedIncomingEvents.Contains(null, viewStateString)) { 1298 return false; // error: this event validation store isn't associated with the incoming __VIEWSTATE 1299 } 1300 _inboundEvents = validatedIncomingEvents; 1301 1302 if (_clientScriptManager._owner.IsCallback) { 1303 // Seed the outbound provider with the valid inbound values; clone so that any outbound values 1304 // added during page processing aren't accidentally treated as valid inbound values. 1305 EventValidationStore clonedEventValidationStore = validatedIncomingEvents.Clone(); 1306 _outboundEvents = clonedEventValidationStore; 1307 } 1308 return true; 1309 } 1310 } 1311 1312 // provides the legacy implementation of event validation (before DevDiv #233564) 1313 private sealed class LegacyEventValidationProvider : IEventValidationProvider { 1314 private readonly ClientScriptManager _clientScriptManager; 1315 private ArrayList _validEventReferences; 1316 private HybridDictionary _clientPostBackValidatedEventTable; 1317 LegacyEventValidationProvider(ClientScriptManager clientScriptManager)1318 internal LegacyEventValidationProvider(ClientScriptManager clientScriptManager) { 1319 _clientScriptManager = clientScriptManager; 1320 } 1321 ComputeHashKey(String uniqueId, String argument)1322 private static int ComputeHashKey(String uniqueId, String argument) { 1323 if (String.IsNullOrEmpty(argument)) { 1324 return StringUtil.GetStringHashCode(uniqueId); 1325 } 1326 1327 return StringUtil.GetStringHashCode(uniqueId) ^ StringUtil.GetStringHashCode(argument); 1328 } 1329 GetEventValidationStoreObject()1330 public object GetEventValidationStoreObject() { 1331 // We only produce the object to be serialized if there is data in the store 1332 if (_validEventReferences != null && _validEventReferences.Count > 0) { 1333 return _validEventReferences; 1334 } 1335 else { 1336 return null; 1337 } 1338 } 1339 IsValid(string uniqueId, string argument)1340 public bool IsValid(string uniqueId, string argument) { 1341 if (_clientPostBackValidatedEventTable == null) { 1342 return false; 1343 } 1344 1345 #if DEBUGEVENTVALIDATION 1346 String hashCode = uniqueId + "@" + argument; 1347 #else 1348 int hashCode = ComputeHashKey(uniqueId, argument); 1349 #endif //DEBUGEVENTVALIDATION 1350 1351 return _clientPostBackValidatedEventTable.Contains(hashCode); 1352 } 1353 RegisterForEventValidation(string uniqueId, string argument)1354 public void RegisterForEventValidation(string uniqueId, string argument) { 1355 #if DEBUGEVENTVALIDATION 1356 string key = uniqueId + "@" + argument; 1357 #else 1358 int key = ComputeHashKey(uniqueId, argument); 1359 #endif //DEBUGEVENTVALIDATION 1360 1361 string stateString = _clientScriptManager._owner.ClientState; 1362 if (stateString == null) { 1363 stateString = String.Empty; 1364 } 1365 1366 if (_validEventReferences == null) { 1367 if (_clientScriptManager._owner.IsCallback) { 1368 _clientScriptManager.EnsureEventValidationFieldLoaded(); 1369 if (_validEventReferences == null) { 1370 _validEventReferences = new ArrayList(); 1371 } 1372 } 1373 else { 1374 _validEventReferences = new ArrayList(); 1375 _validEventReferences.Add( 1376 StringUtil.GetStringHashCode(stateString)); 1377 } 1378 } 1379 1380 #if DEBUGEVENTVALIDATION 1381 Debug.Assert(!_validEventReferences.Contains(key)); 1382 #endif //DEBUGEVENTVALIDATION 1383 1384 _validEventReferences.Add(key); 1385 } 1386 TryLoadEventValidationField(object eventValidationField)1387 public bool TryLoadEventValidationField(object eventValidationField) { 1388 ArrayList validatedClientEvents = eventValidationField as ArrayList; 1389 if (validatedClientEvents == null || validatedClientEvents.Count < 1) { 1390 return true; // empty collection is not an error condition 1391 } 1392 1393 Debug.Assert(_clientPostBackValidatedEventTable == null); 1394 int viewStateHashCode = (int)validatedClientEvents[0]; 1395 1396 string viewStateString = _clientScriptManager._owner.RequestViewStateString; 1397 1398 if (viewStateHashCode != StringUtil.GetStringHashCode(viewStateString)) { 1399 return false; // hash mismatch is an error condition 1400 } 1401 1402 _clientPostBackValidatedEventTable = new HybridDictionary(validatedClientEvents.Count - 1, true); 1403 1404 // Ignore the first item in the arrayList, which is the controlstate 1405 for (int index = 1; index < validatedClientEvents.Count; index++) { 1406 #if DEBUGEVENTVALIDATION 1407 string hashKey = (string)validatedClientEvents[index]; 1408 #else 1409 int hashKey = (int)validatedClientEvents[index]; 1410 #endif //DEBUGEVENTVALIDATION 1411 _clientPostBackValidatedEventTable[hashKey] = null; 1412 } 1413 1414 if (_clientScriptManager._owner.IsCallback) { 1415 _validEventReferences = validatedClientEvents; 1416 } 1417 return true; 1418 } 1419 } 1420 } 1421 1422 [Serializable] 1423 internal class ScriptKey { 1424 [NonSerialized] 1425 private Type _type; 1426 private string _typeNameForSerialization; 1427 private string _key; 1428 private bool _isInclude; 1429 private bool _isResource; 1430 ScriptKey(Type type, string key)1431 internal ScriptKey(Type type, string key) : this(type, key, false, false) { 1432 } 1433 ScriptKey(Type type, string key, bool isInclude, bool isResource)1434 internal ScriptKey(Type type, string key, bool isInclude, bool isResource) { 1435 Debug.Assert(type != null); 1436 _type = type; 1437 1438 // To treat nulls the same as empty strings, make them empty string. 1439 if (key == null) { 1440 key = String.Empty; 1441 } 1442 _key = key; 1443 _isInclude = isInclude; 1444 _isResource = isResource; 1445 } 1446 1447 public Assembly Assembly { 1448 get { 1449 return _type == null ? null : AssemblyResourceLoader.GetAssemblyFromType(_type); 1450 } 1451 } 1452 1453 public bool IsResource { 1454 get { 1455 return _isResource; 1456 } 1457 } 1458 1459 public string Key { 1460 get { 1461 return _key; 1462 } 1463 } 1464 GetHashCode()1465 public override int GetHashCode() { 1466 return WebUtil.HashCodeCombiner.CombineHashCodes(_type.GetHashCode(), _key.GetHashCode(), 1467 _isInclude.GetHashCode()); 1468 } 1469 Equals(object o)1470 public override bool Equals(object o) { 1471 ScriptKey key = (ScriptKey)o; 1472 return (key._type == _type) && (key._key == _key) && (key._isInclude == _isInclude); 1473 } 1474 1475 [OnSerializing()] OnSerializingMethod(StreamingContext context)1476 private void OnSerializingMethod(StreamingContext context) { 1477 // create a string representation of _type 1478 _typeNameForSerialization = System.Web.UI.Util.GetAssemblyQualifiedTypeName(_type); 1479 } 1480 1481 [OnDeserialized()] OnDeserializedMethod(StreamingContext context)1482 private void OnDeserializedMethod(StreamingContext context) { 1483 // re-create _type from its string representation 1484 _type = BuildManager.GetType(_typeNameForSerialization, true /*throwOnFail*/, false /*ignoreCase*/); 1485 } 1486 } 1487 } 1488