1 //------------------------------------------------------------------------------
2 // <copyright file="AsyncPostBackTrigger.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.Diagnostics.CodeAnalysis;
11     using System.Globalization;
12     using System.Reflection;
13     using System.Web;
14     using System.Web.UI;
15     using System.Web.Resources;
16     using System.Web.Util;
17 
18     public class AsyncPostBackTrigger : UpdatePanelControlTrigger {
19 
20         private IScriptManagerInternal _scriptManager;
21 
22         private Control _associatedControl;
23         private static MethodInfo _eventHandler;
24         private bool _eventHandled;
25         private string _eventName;
26 
AsyncPostBackTrigger()27         public AsyncPostBackTrigger() {
28         }
29 
AsyncPostBackTrigger(IScriptManagerInternal scriptManager)30         internal AsyncPostBackTrigger(IScriptManagerInternal scriptManager) {
31             _scriptManager = scriptManager;
32         }
33 
34         private static MethodInfo EventHandler {
35             get {
36                 if (_eventHandler == null) {
37                     _eventHandler = typeof(AsyncPostBackTrigger).GetMethod("OnEvent");
38                 }
39                 return _eventHandler;
40             }
41         }
42 
43         [
44         SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "ID"),
45         TypeConverter("System.Web.UI.Design.AsyncPostBackTriggerControlIDConverter, " +
46             AssemblyRef.SystemWebExtensionsDesign)
47         ]
48         public new string ControlID {
49             get {
50                 return base.ControlID;
51             }
52             set {
53                 base.ControlID = value;
54             }
55         }
56 
57         [
58         DefaultValue(""),
59         Category("Behavior"),
60         ResourceDescription("AsyncPostBackTrigger_EventName"),
61         TypeConverter("System.Web.UI.Design.AsyncPostBackTriggerEventNameConverter, " +
62             AssemblyRef.SystemWebExtensionsDesign),
63         ]
64         public string EventName {
65             get {
66                 if (_eventName == null) {
67                     return String.Empty;
68                 }
69                 return _eventName;
70             }
71             set {
72                 _eventName = value;
73             }
74         }
75 
76         internal IScriptManagerInternal ScriptManager {
77             get {
78                 if (_scriptManager == null) {
79                     Page page = Owner.Page;
80                     if (page == null) {
81                         throw new InvalidOperationException(AtlasWeb.Common_PageCannotBeNull);
82                     }
83                     _scriptManager = UI.ScriptManager.GetCurrent(page);
84                     if (_scriptManager == null) {
85                         throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.Common_ScriptManagerRequired, Owner.ID));
86                     }
87                 }
88                 return _scriptManager;
89             }
90         }
91 
Initialize()92         protected internal override void Initialize() {
93             base.Initialize();
94 
95             _associatedControl = FindTargetControl(true);
96 
97             ScriptManager.RegisterAsyncPostBackControl(_associatedControl);
98 
99             string eventName = EventName;
100             if (eventName.Length != 0) {
101                 // If EventName is specified, attach our event handler to it
102                 EventInfo eventInfo = _associatedControl.GetType().GetEvent(eventName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
103                 if (eventInfo == null) {
104                     throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.AsyncPostBackTrigger_CannotFindEvent, eventName, ControlID, Owner.ID));
105                 }
106 
107                 MethodInfo handlerMethod = eventInfo.EventHandlerType.GetMethod("Invoke");
108                 ParameterInfo[] parameters = handlerMethod.GetParameters();
109                 if (!handlerMethod.ReturnType.Equals(typeof(void)) ||
110                     (parameters.Length != 2) ||
111                     (typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType) == false)) {
112                     throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.AsyncPostBackTrigger_InvalidEvent, eventName, ControlID, Owner.ID));
113                 }
114 
115                 Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, this, EventHandler);
116                 eventInfo.AddEventHandler(_associatedControl, handler);
117             }
118         }
119 
HasTriggered()120         protected internal override bool HasTriggered() {
121             if (!String.IsNullOrEmpty(EventName)) {
122                 // If EventName is specified we are triggered if our event was raised
123                 return _eventHandled;
124             }
125             else {
126                 // If EventName is not specified, check if the control that caused the
127                 // postback either has the exact UniqueID we're looking for, or at least
128                 // begins with it.
129                 string sourceElement = ScriptManager.AsyncPostBackSourceElementID;
130                 return
131                     (sourceElement == _associatedControl.UniqueID) ||
132                     (sourceElement.StartsWith(_associatedControl.UniqueID + "$", StringComparison.Ordinal));
133             }
134         }
135 
136         // DevDiv Bugs 127369: This method should be private and the reflection lookup should assert reflection permission
137         // so the private reflection works in medium trust.
138         // However, ASP.NET AJAX 1.0 was released with this method public. Since it would be a breaking change to make it private
139         // now, it was decided to leave it as is.
140         [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers",
141             Justification="TODO: This will be fixed in fc_serverfx")]
OnEvent(object sender, EventArgs e)142         public void OnEvent(object sender, EventArgs e) {
143             _eventHandled = true;
144         }
145 
146         [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
ToString()147         public override string ToString() {
148             if (String.IsNullOrEmpty(ControlID)) {
149                 return "AsyncPostBack";
150             }
151             else {
152                 return "AsyncPostBack: " + ControlID +
153                     (String.IsNullOrEmpty(EventName) ? String.Empty : ("." + EventName));
154             }
155         }
156     }
157 }
158