Support for event validation
authorMarek Habersack <grendel@twistedcode.net>
Fri, 17 Nov 2006 18:56:07 +0000 (18:56 -0000)
committerMarek Habersack <grendel@twistedcode.net>
Fri, 17 Nov 2006 18:56:07 +0000 (18:56 -0000)
svn path=/trunk/mcs/; revision=68082

29 files changed:
mcs/class/System.Web/ChangeLog
mcs/class/System.Web/System.Web.UI.HtmlControls/ChangeLog
mcs/class/System.Web/System.Web.UI.HtmlControls/HtmlButton.cs
mcs/class/System.Web/System.Web.UI.HtmlControls/HtmlInputButton.cs
mcs/class/System.Web/System.Web.UI.HtmlControls/HtmlInputCheckBox.cs
mcs/class/System.Web/System.Web.UI.HtmlControls/HtmlInputHidden.cs
mcs/class/System.Web/System.Web.UI.HtmlControls/HtmlInputImage.cs
mcs/class/System.Web/System.Web.UI.HtmlControls/HtmlInputRadioButton.cs
mcs/class/System.Web/System.Web.UI.HtmlControls/HtmlInputSubmit.cs
mcs/class/System.Web/System.Web.UI.HtmlControls/HtmlInputText.cs
mcs/class/System.Web/System.Web.UI.HtmlControls/HtmlSelect.cs
mcs/class/System.Web/System.Web.UI.HtmlControls/HtmlTextArea.cs
mcs/class/System.Web/System.Web.UI.WebControls/BulletedList.cs
mcs/class/System.Web/System.Web.UI.WebControls/Button.cs
mcs/class/System.Web/System.Web.UI.WebControls/Calendar.cs
mcs/class/System.Web/System.Web.UI.WebControls/ChangeLog
mcs/class/System.Web/System.Web.UI.WebControls/CheckBox.cs
mcs/class/System.Web/System.Web.UI.WebControls/DropDownList.cs
mcs/class/System.Web/System.Web.UI.WebControls/FormView.cs
mcs/class/System.Web/System.Web.UI.WebControls/ImageButton.cs
mcs/class/System.Web/System.Web.UI.WebControls/ListBox.cs
mcs/class/System.Web/System.Web.UI.WebControls/RadioButtonList.cs
mcs/class/System.Web/System.Web.UI.WebControls/TextBox.cs
mcs/class/System.Web/System.Web.UI/ChangeLog
mcs/class/System.Web/System.Web.UI/ClientScriptManager.cs
mcs/class/System.Web/System.Web.UI/Page.cs
mcs/class/System.Web/System.Web.UI/PageLifeCycle.cs [new file with mode: 0644]
mcs/class/System.Web/System.Web.UI/PostBackOptions.cs
mcs/class/System.Web/System.Web.dll.sources

index 04d600326eb7a0cf2ded926a40cc628cc4a67706..39523e501ca665ed4cd49af2a0f7b77a032a3df3 100644 (file)
@@ -2,7 +2,8 @@
 
        * System.Web.dll.sources: Added
        System.Web.Compilation/ForceCopyBuildProvider.cs and
-       System.Web.Compilation/MasterPageBuildProvider.cs
+       System.Web.Compilation/MasterPageBuildProvider.cs and
+       System.Web.UI/PageLifeCycle.cs
 
 2006-11-09 Vladimir Krasnov <vladimirk@mainsoft.com>
 
index cdf12cc4710e7f75623b4e5724008fae4b855f2f..0813c290e77f938e4dedc2d9294a89110d5a2370 100644 (file)
@@ -1,3 +1,23 @@
+2006-11-17  Marek Habersack  <grendello@gmail.com>
+
+       * HtmlInputHidden.cs: Added support for event validation.
+
+       * HtmlInputCheckBox.cs: Added support for event validation.
+
+       * HtmlInputImage.cs: Added support for event validation.
+
+       * HtmlInputButton.cs: Added support for event validation.
+
+       * HtmlSelect.cs: Added support for event validation.
+
+       * HtmlTextArea.cs: Added support for event validation.
+
+       * HtmlButton.cs: Added support for event validation.
+
+       * HtmlInputRadioButton.cs: Added support for event validation.
+
+       * HtmlInputText.cs: Added support for event validation.
+
 2006-11-13  Igor Zelmanovich  <igorz@mainsoft.com>
 
        * HtmlContainerControl.cs: fixed: InnerHtml property  
index d5900fa451e0b0b35321330609019dee7ad6c775..f7aab7c6854670fc93e6a01f26f8713f4101e291 100644 (file)
@@ -97,7 +97,7 @@ namespace System.Web.UI.HtmlControls {
 #endif
                        OnServerClick (EventArgs.Empty);
                }
-
+               
 #if NET_2_0
                protected internal
 #else          
@@ -121,6 +121,7 @@ namespace System.Web.UI.HtmlControls {
 #if NET_2_0
                        if (Page != null && Events [ServerClickEvent] != null) {
                                PostBackOptions options = GetPostBackOptions ();
+                               Page.ClientScript.RegisterForEventValidation (options);
                                Attributes ["onclick"] += Page.ClientScript.GetPostBackEventReference (options);
                                writer.WriteAttribute ("language", "javascript");
                        }
index b7961e5e3f33a955472f52c57f6f087e57e13368..1defe4341f65c1d9e3c14ea9b3366d68ca6348b2 100644 (file)
@@ -177,6 +177,7 @@ namespace System.Web.UI.HtmlControls {
                                }
                                if (Page != null) {
                                        PostBackOptions options = GetPostBackOptions ();
+                                       Page.ClientScript.RegisterForEventValidation (options);
                                        onclick += Page.ClientScript.GetPostBackEventReference (options);
                                }
 
index a0981cfa2079264ef438223dacc1d0310e057956..23dd7345a2382b924be1016410531c4645134731 100644 (file)
@@ -87,6 +87,15 @@ namespace System.Web.UI.HtmlControls
                        }
                }
 
+#if NET_2_0
+               protected override void RenderAttributes (HtmlTextWriter writer)
+               {
+                       if (Page != null)
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID);
+                       base.RenderAttributes (writer);
+               }
+#endif
+
 #if NET_2_0
                protected internal
 #else
index 592a9c169ae4435cb98eb28ed4e122428160f8ab..efb5df3931445962a114a49469dc726f63300232 100644 (file)
@@ -95,6 +95,13 @@ namespace System.Web.UI.HtmlControls {
                }
 
 #if NET_2_0
+               protected override void RenderAttributes (HtmlTextWriter writer)
+               {
+                       if (Page != null)
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID);
+                       base.RenderAttributes (writer);
+               }               
+
                protected internal
 #else
                protected
index 864c358250ec8b06598d1078d70ded7d8374bae6..9e441310ab7ca4c704d2ea32d1625cbde2c99a56 100644 (file)
@@ -246,6 +246,9 @@ namespace System.Web.UI.HtmlControls {
                protected override void RenderAttributes (HtmlTextWriter writer)
                {
 #if NET_2_0
+                       if (Page != null)
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID);
+                       
                        if (CausesValidation && Page != null && Page.AreValidatorsUplevel (ValidationGroup)) {
                                ClientScriptManager csm = Page.ClientScript;
                                Attributes ["onclick"] += csm.GetClientValidationEvent (ValidationGroup);
index 2912384b2c2ecb31e962a49592e1e7046423e762..0b26f1ccf7291eb5744a7e514c7f9088d8b6ef81 100644 (file)
@@ -96,7 +96,6 @@ namespace System.Web.UI.HtmlControls {
                        }
                }
 
-
 #if NET_2_0
                protected internal
 #else
@@ -120,6 +119,10 @@ namespace System.Web.UI.HtmlControls {
 
                protected override void RenderAttributes (HtmlTextWriter writer)
                {
+#if NET_2_0
+                       if (Page != null)
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID, Value);
+#endif
                        writer.WriteAttribute ("value", Value);
                        Attributes.Remove ("value");
                        base.RenderAttributes (writer);
index 2ef52266103f5b0e960af73e092595eab195baaf..9430d0d4f03b410652989ea6df7695c157b97426 100644 (file)
@@ -50,7 +50,7 @@ namespace System.Web.UI.HtmlControls {
                        : base (type)
                {
                }
-
+               
                [MonoTODO ("why our own version?")]
                void IPostBackEventHandler.RaisePostBackEvent (string eventArgument)
                {
index b41f019d9aff3c85459cd38f0ab96a5fd0ea3f81..43f777609471822d2f502b68214096e74134706e 100644 (file)
@@ -110,6 +110,14 @@ namespace System.Web.UI.HtmlControls {
                }
 
 
+#if NET_2_0
+               protected internal override void Render (HtmlTextWriter writer)
+               {
+                       Page.ClientScript.RegisterForEventValidation (this.UniqueID);
+                       base.Render (writer);
+               }
+#endif
+
 #if NET_2_0
                protected internal
 #else          
index dfec4a6adb4ec89151d905e59829497a33abb120..5c45281cbd06714cc7d41076e351d43768e29717 100644 (file)
@@ -611,6 +611,10 @@ namespace System.Web.UI.HtmlControls
                
                protected override void RenderAttributes (HtmlTextWriter w)
                {
+#if NET_2_0
+                       if (Page != null)
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID);
+#endif
                        /* If there is no "name" attribute,
                         * LoadPostData doesn't work...
                         */
@@ -645,7 +649,6 @@ namespace System.Web.UI.HtmlControls
                        int count = items.Count;
                        for (int i = 0; i < count; i++) {
                                ListItem item = items[i];
-
                                w.Indent++;
                                
                                /* Write the <option> elements this
index 1d801f3bf6d318a2bab03f93f980c09c61ab7321..62eda3162e201cd32e9f16b28000690fe5a1c9e7 100644 (file)
@@ -137,6 +137,10 @@ namespace System.Web.UI.HtmlControls {
 
                protected override void RenderAttributes (HtmlTextWriter writer)
                {
+#if NET_2_0
+                       if (Page != null)
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID);
+#endif
                        if (Attributes ["name"] == null) {
                                writer.WriteAttribute ("name", Name);
                        }
index 9722e2bb65f2452145bed6b000e7fe123714f4bb..2ad01972b7b38d6595e2a5c2965b5f24cc2bb82b 100644 (file)
@@ -172,7 +172,14 @@ namespace System.Web.UI.WebControls {
                protected internal override void RenderContents (HtmlTextWriter writer)
                {
                        int idx = 0;
+#if NET_2_0
+                       bool havePage = Page != null;
+#endif
                        foreach (ListItem i in Items) {
+#if NET_2_0
+                               if (havePage)
+                                       Page.ClientScript.RegisterForEventValidation (this.UniqueID, i.Value.ToString ());
+#endif
                                writer.RenderBeginTag (HtmlTextWriterTag.Li);
                                this.RenderBulletText (i, idx ++, writer);
                                writer.RenderEndTag ();
index 6efbe27240acef1818a0de995b5779d58a746bb3..9f357cdbf017b538c51cf30d2342d131f8e46ffb 100644 (file)
@@ -164,9 +164,13 @@ namespace System.Web.UI.WebControls {
 #endif         
 
                protected override void AddAttributesToRender (HtmlTextWriter writer) {
-                       if (Page != null)
+                       if (Page != null) {
+#if NET_2_0
+                               Page.ClientScript.RegisterForEventValidation (GetPostBackOptions ());
+#endif
                                Page.VerifyRenderingInServerForm (this);
-
+                       }
+                       
 #if NET_2_0
                        writer.AddAttribute (HtmlTextWriterAttribute.Type, UseSubmitBehavior ? "submit" : "button");
                        writer.AddAttribute (HtmlTextWriterAttribute.Name, UniqueID);
@@ -270,14 +274,14 @@ namespace System.Web.UI.WebControls {
                protected internal
 #else          
                protected
-#endif         
+#endif
                override void RenderContents (HtmlTextWriter writer)
-               {
-               }
-
+                {
+                }
+               
                [WebSysDescription ("")]
                [WebCategory ("Action")]
-               public event EventHandler Click
+                       public event EventHandler Click
                {
                        add {
                                Events.AddHandler (ClickEvent, value);
index e11784290353f52f6cdd239c2ebc71e2be41f328..9d7ce472fe1e24b8f0aeb9b284a10ecd4ff4cb64 100644 (file)
@@ -786,6 +786,10 @@ namespace System.Web.UI.WebControls {
 #endif         
                override void Render (HtmlTextWriter writer)
                {
+#if NET_2_0
+                       if (Page != null)
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID);
+#endif
                        Table table = new Table ();
                        table.CellSpacing = CellSpacing;
                        table.CellPadding = CellPadding;
index a7eec87321c6b8e43ea3d13513437118b08316ab..21d5d3ed17d7f9c5ec556fe780c0b9c7ae8fb853 100644 (file)
@@ -1,3 +1,25 @@
+2006-11-17  Marek Habersack  <grendello@gmail.com>
+
+       * ImageButton.cs: Added support for event validation.
+
+       * ListBox.cs: Added support for event validation.
+
+       * Calendar.cs: Added support for event validation.
+
+       * DropDownList.cs: Added support for event validation.
+
+       * FormView.cs: Added support for event validation.
+
+       * RadioButtonList.cs: Added support for event validation.
+
+       * TextBox.cs: Added support for event validation.
+
+       * BulletedList.cs: Added support for event validation.
+
+       * CheckBox.cs: Added support for event validation.
+
+       * Button.cs: Added support for event validation.
+
 2006-11-16 Igor Zelmanovich <igorz@mainsoft.com>
 
        * CreateUserWizard.cs: fixed: ActiveStepIndex property.
index b01661d6439d46fd541c7ec6f24e252fbec12f0d..d8cb8bc83357bd1200843ad75da48adf299b95a1 100644 (file)
@@ -362,9 +362,13 @@ namespace System.Web.UI.WebControls {
 #endif         
                override void Render (HtmlTextWriter w)
                {
-                       if (Page != null)
+                       if (Page != null) {
+#if NET_2_0
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID);
+#endif
                                Page.VerifyRenderingInServerForm (this);
-
+                       }
+                       
                        bool need_span = ControlStyleCreated && !ControlStyle.IsEmpty;
                        if (need_span)
                                ControlStyle.AddAttributesToRender (w, this);
index d8ce64c9ee6e0cd01b3b428313b9bb0e1c0b714c..65932b63ec24a19dce74674f276fadeba89c4bda 100644 (file)
@@ -180,7 +180,9 @@ namespace System.Web.UI.WebControls {
 
                        for (int i = 0; i < count; i++) {
                                item = Items[i];
-
+#if NET_2_0
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID, item.Value.ToString ());
+#endif
                                writer.WriteBeginTag("option");
                                if (item.Selected) {
                                        if (selected) {
index bf360efa6f76d2b85d5494745da446b167c43411..a79d69714125fdcfabd7572aa9b84ab2ad6f9797 100644 (file)
@@ -1464,6 +1464,10 @@ namespace System.Web.UI.WebControls
                \r
                protected internal override void Render (HtmlTextWriter writer)\r
                {\r
+#if NET_2_0\r
+                       if (Page != null)\r
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID);\r
+#endif\r
                        PrepareControlHierarchy ();\r
                        \r
                        if (table == null)\r
index b082c6571728ecc469b18c05938f26c50e11c31d..7491d529a63774ad4011516dbc61a469cdf942c6 100644 (file)
@@ -209,9 +209,13 @@ namespace System.Web.UI.WebControls {
 
                protected override void AddAttributesToRender (HtmlTextWriter writer)
                {
-                       if (Page != null)
+                       if (Page != null) {
+#if NET_2_0
+                               Page.ClientScript.RegisterForEventValidation (GetPostBackOptions ());
+#endif
                                Page.VerifyRenderingInServerForm (this);
-
+                       }
+                       
                        writer.AddAttribute (HtmlTextWriterAttribute.Type, "image");
                        writer.AddAttribute (HtmlTextWriterAttribute.Name, UniqueID);
 #if NET_2_0
index eabfef92e34ccf9c77dde9a906179049a257e52d..a93a607d5833f70183e8cf4fc3007d893675c81d 100644 (file)
@@ -183,7 +183,14 @@ namespace System.Web.UI.WebControls {
 #endif         
                override void RenderContents (HtmlTextWriter writer)
                {
+#if NET_2_0
+                       bool havePage = Page != null;
+#endif
                        foreach (ListItem item in Items) {
+#if NET_2_0
+                               if (havePage)
+                                       Page.ClientScript.RegisterForEventValidation (this.UniqueID, item.Value.ToString ());
+#endif
                                writer.WriteBeginTag ("option");
                                if (item.Selected) {
                                        writer.WriteAttribute ("selected", "selected", false);
index cf612cac9a14b0f8f70f261fca91309b2d2338f7..fa978c770e9ee757bdbc97f5575290fe1fc9b3d6 100644 (file)
@@ -339,6 +339,9 @@ namespace System.Web.UI.WebControls {
                override void Render (HtmlTextWriter writer)
                {
 #if NET_2_0
+                       if (Page != null)
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID);
+
                        if (Items.Count == 0)
                                return;
 #endif
index ba0bf4466236b53c910e5ec0fef5411f19bc746c..6fdfc70aaa4e66a9f9c1fc64612640b0f8ac9018 100644 (file)
@@ -140,6 +140,10 @@ namespace System.Web.UI.WebControls {
 #endif         
                override void Render (HtmlTextWriter w)
                {
+#if NET_2_0
+                       if (Page != null)
+                               Page.ClientScript.RegisterForEventValidation (this.UniqueID);
+#endif
                        // Why didn't msft just override RenderContents!?
                        RenderBeginTag (w);
                        if (TextMode == TextBoxMode.MultiLine)
index 4d562ccddaf2f7a474fe627033425cd3e53b5d76..38f7ff023417f112b5973bd8ca25a7e45df35087 100644 (file)
@@ -1,3 +1,31 @@
+2006-11-17  Marek Habersack  <grendello@gmail.com>
+
+       * PostBackOptions.cs: Renamed the constructors parameters to match
+       those Microsoft .NET uses.
+       targetControl must not be passed null to the constructor.
+
+       * ClientScriptManager.cs: Support for event validation.
+       Implemented a GetPostBackHyperlink overload.
+       Implemented the RegisterForEventValidation methods.
+       Implemented the ValidateEvent method.
+       Added support for saving/restoring event validation state.
+
+       * Page.cs: EnableEventValidation can be set only from the config
+       files (the <pages> element), the Page directive or from
+       Page_Init. After Page_Init returns, an exception is thrown.
+       Made GetFormatter internal, so that ClientScriptManager can use
+       it.
+       Added the internal LifeCycle property which contains the current
+       life cycle stage of the page request processing.
+       Added calls to save/restore event validation state.
+       Added checks for whether child controls of the page support event
+       validation or not.
+       Added calls to ClientScriptManager.ValidateEvent in appropriate
+       places.
+
+       * PageLifeCycle.cs: Added the PageLifeCycle enum, used in event
+       validation.
+
 2006-11-16 Gonzalo Paniagua Javier <gonzalo@ximian.com>
 
        * LosFormatter.cs:
index da9d2a758e494c5eeffdd81c0be43fdeecc10679..89840267d1ac5fbb549f7f00cff925773fd8e7cf 100644 (file)
@@ -34,6 +34,9 @@
 
 using System;
 using System.Collections;
+#if NET_2_0
+using System.Collections.Generic;
+#endif
 using System.Text;
 
 namespace System.Web.UI
@@ -52,7 +55,10 @@ namespace System.Web.UI
                ScriptEntry submitStatements;
                ScriptEntry scriptIncludes;
                Page page;
-       
+#if NET_2_0
+               List <int> eventValidationValues;
+#endif
+               
                internal ClientScriptManager (Page page)
                {
                        this.page = page;
@@ -70,6 +76,15 @@ namespace System.Web.UI
                        return "javascript:" + GetPostBackEventReference (control, argument);
                }
        
+#if NET_2_0
+               public string GetPostBackClientHyperlink (Control control, string argument, bool registerForEventValidation)
+               {
+                       if (registerForEventValidation)
+                               RegisterForEventValidation (control.UniqueID, argument);
+                       return "javascript:" + GetPostBackEventReference (control, argument);
+               }
+#endif
+               
                public string GetPostBackEventReference (Control control, string argument)
                {
                        page.RequiresPostBackScript ();
@@ -339,35 +354,64 @@ namespace System.Web.UI
                {
                        throw new NotImplementedException ();
                }
-
-               [MonoTODO]
+               
+               // Implemented following the description in http://odetocode.com/Blogs/scott/archive/2006/03/20/3145.aspx
+               private int CalculateEventHash (string uniqueId, string argument)
+               {
+                       int uniqueIdHash = uniqueId.GetHashCode ();
+                       int argumentHash = (argument == null) ? 0 : argument.GetHashCode ();
+                       return (uniqueIdHash ^ argumentHash);
+               }
+               
                public void RegisterForEventValidation (PostBackOptions options)
                {
-                       throw new NotImplementedException ();
+                       // MS.NET does not check for options == null, so we won't too...
+                       RegisterForEventValidation (options.TargetControl.UniqueID, options.Argument);
                }
                
-               [MonoTODO]
                public void RegisterForEventValidation (string uniqueId)
                {
-                       throw new NotImplementedException ();
+                       RegisterForEventValidation (uniqueId, null);
                }
-
-               [MonoTODO]
+               
                public void RegisterForEventValidation (string uniqueId, string argument)
                {
-                       throw new NotImplementedException ();
+                       if (!page.EnableEventValidation)
+                               return;
+                       if (uniqueId == null || uniqueId.Length == 0)
+                               return;
+                       if (page.LifeCycle < PageLifeCycle.Render)
+                               throw new InvalidOperationException ("RegisterForEventValidation may only be called from the Render method");
+                       if (eventValidationValues == null)
+                               eventValidationValues = new List <int> ();
+
+                       
+                       int hash = CalculateEventHash (uniqueId, argument);
+                       if (eventValidationValues.BinarySearch (hash) < 0)
+                               eventValidationValues.Add (hash);
                }
 
-               [MonoTODO]
                public void ValidateEvent (string uniqueId)
                {
-                       throw new NotImplementedException ();
+                       ValidateEvent (uniqueId, null);
                }
 
-               [MonoTODO]
                public void ValidateEvent (string uniqueId, string argument)
                {
-                       throw new NotImplementedException ();
+                       if (uniqueId == null || uniqueId.Length == 0)
+                               throw new ArgumentException ("must not be null or empty", "uniqueId");
+                       if (!page.EnableEventValidation)
+                               return;
+                       if (eventValidationValues == null)
+                               goto bad;
+                       
+                       int hash = CalculateEventHash (uniqueId, argument);
+                       if (eventValidationValues.BinarySearch (hash) < 0)
+                               goto bad;
+                       return;
+                       
+                       bad:
+                       throw new ArgumentException ("Invalid postback or callback argument. Event validation is enabled using <pages enableEventValidation=\"true\"/> in configuration or <%@ Page EnableEventValidation=\"true\" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.");
                }
 #endif
                void WriteScripts (HtmlTextWriter writer, ScriptEntry scriptList)
@@ -377,6 +421,30 @@ namespace System.Web.UI
                                scriptList = scriptList.Next;
                        }
                }
+
+#if NET_2_0
+               internal void RestoreEventValidationState (string fieldValue)
+               {
+                       if (!page.EnableEventValidation || fieldValue == null || fieldValue.Length == 0)
+                               return;
+                       LosFormatter fmt = page.GetFormatter ();
+                       eventValidationValues = (List <int>)fmt.Deserialize (fieldValue);
+               }
+               
+               internal void SaveEventValidationState ()
+               {
+                       if (!page.EnableEventValidation || eventValidationValues == null || eventValidationValues.Count == 0)
+                               return;
+                       eventValidationValues.Sort ();
+                       LosFormatter fmt = page.GetFormatter ();
+                       RegisterHiddenField (EventStateFieldName, fmt.SerializeToBase64 (eventValidationValues));
+               }
+
+               internal string EventStateFieldName
+               {
+                       get { return "__EVENTVALIDATION"; }
+               }
+#endif
                
                internal void WriteHiddenFields (HtmlTextWriter writer)
                {
index d7e6f528425b210b528e8ca0157670a6b5037f9a..65b3b3ac7953dd812c3dbdb8da2f921601fa202d 100644 (file)
@@ -71,6 +71,7 @@ namespace System.Web.UI
 public class Page : TemplateControl, IHttpHandler
 {
 #if NET_2_0
+       private PageLifeCycle _lifeCycle = PageLifeCycle.Unknown;
        private bool _eventValidation = true;
 #endif
        private bool _viewState = true;
@@ -281,7 +282,15 @@ public class Page : TemplateControl, IHttpHandler
 #if NET_2_0
        public virtual bool EnableEventValidation {
                get { return _eventValidation; }
-               set { _eventValidation = value;}
+               set {
+                       if (_lifeCycle > PageLifeCycle.Init)
+                               throw new InvalidOperationException ("The 'EnableEventValidation' property can be set only in the Page_init, the Page directive or in the <pages> configuration section.");
+                       _eventValidation = value;
+               }
+       }
+
+       internal PageLifeCycle LifeCycle {
+               get { return _lifeCycle; }
        }
 #endif
 
@@ -942,7 +951,7 @@ public class Page : TemplateControl, IHttpHandler
                scriptManager.WriteClientScriptBlocks (writer);
        }
 
-       LosFormatter GetFormatter ()
+       internal LosFormatter GetFormatter ()
        {
 #if NET_2_0
                PagesSection config = (PagesSection) WebConfigurationManager.GetSection ("system.web/pages");
@@ -983,7 +992,10 @@ public class Page : TemplateControl, IHttpHandler
 
                if (!postBackScriptRendered && requiresPostBackScript)
                        RenderPostBackScript (writer, formUniqueID);
-
+               
+#if NET_2_0
+               scriptManager.SaveEventValidationState ();
+#endif
                scriptManager.WriteHiddenFields (writer);
                scriptManager.WriteClientScriptIncludes (writer);
                scriptManager.WriteStartupScriptBlocks (writer);
@@ -1069,6 +1081,9 @@ public class Page : TemplateControl, IHttpHandler
        public void ProcessRequest (HttpContext context)
 #endif
        {
+#if NET_2_0
+               _lifeCycle = PageLifeCycle.Unknown;
+#endif
                _context = context;
                if (clientTarget != null)
                        Request.ClientTarget = clientTarget;
@@ -1096,8 +1111,14 @@ public class Page : TemplateControl, IHttpHandler
                        throw;
                } finally {
                        try {
+#if NET_2_0
+                               _lifeCycle = PageLifeCycle.Unload;
+#endif
                                RenderTrace ();
                                UnloadRecursive (true);
+#if NET_2_0
+                               _lifeCycle = PageLifeCycle.End;
+#endif
                        } catch {}
                        if (Thread.CurrentThread.CurrentCulture.Equals (culture) == false)
                                Thread.CurrentThread.CurrentCulture = culture;
@@ -1120,6 +1141,7 @@ public class Page : TemplateControl, IHttpHandler
                _requestValueCollection = this.DeterminePostBackMode();
 
 #if NET_2_0
+               _lifeCycle = PageLifeCycle.Start;
                // http://msdn2.microsoft.com/en-us/library/ms178141.aspx
                if (_requestValueCollection != null) {
                        if (!isCrossPagePostBack && _requestValueCollection [PreviousPageID] != null && _requestValueCollection [PreviousPageID] != Request.FilePath) {
@@ -1131,22 +1153,28 @@ public class Page : TemplateControl, IHttpHandler
                        }
                }
 
+               _lifeCycle = PageLifeCycle.PreInit;
                OnPreInit (EventArgs.Empty);
 
                InitializeTheme ();
                ApplyMasterPage ();
+               _lifeCycle = PageLifeCycle.Init;
 #endif
                Trace.Write ("aspx.page", "Begin Init");
                InitRecursive (null);
                Trace.Write ("aspx.page", "End Init");
 
 #if NET_2_0
+               _lifeCycle = PageLifeCycle.InitComplete;
                OnInitComplete (EventArgs.Empty);
 #endif
                        
                renderingForm = false;  
 #if NET_2_0
                if (IsPostBack || IsCallback) {
+                       _lifeCycle = PageLifeCycle.PreLoad;
+                       if (_requestValueCollection != null)
+                               scriptManager.RestoreEventValidationState (_requestValueCollection [scriptManager.EventStateFieldName]);
 #else
                if (IsPostBack) {
 #endif
@@ -1160,11 +1188,13 @@ public class Page : TemplateControl, IHttpHandler
 
 #if NET_2_0
                OnPreLoad (EventArgs.Empty);
+               _lifeCycle = PageLifeCycle.Load;
 #endif
 
                LoadRecursive ();
 #if NET_2_0
                if (IsPostBack || IsCallback) {
+                       _lifeCycle = PageLifeCycle.ControlEvents;
 #else
                if (IsPostBack) {
 #endif
@@ -1180,6 +1210,7 @@ public class Page : TemplateControl, IHttpHandler
                }
                
 #if NET_2_0
+               _lifeCycle = PageLifeCycle.LoadComplete;
                OnLoadComplete (EventArgs.Empty);
 
                if (IsCrossPagePostBack)
@@ -1192,6 +1223,8 @@ public class Page : TemplateControl, IHttpHandler
                        callbackOutput.Flush ();
                        return;
                }
+
+               _lifeCycle = PageLifeCycle.PreRender;
 #endif
                
                Trace.Write ("aspx.page", "Begin PreRender");
@@ -1207,7 +1240,9 @@ public class Page : TemplateControl, IHttpHandler
                Trace.Write ("aspx.page", "End SaveViewState");
                
 #if NET_2_0
+               _lifeCycle = PageLifeCycle.SaveStateComplete;
                OnSaveStateComplete (EventArgs.Empty);
+               _lifeCycle = PageLifeCycle.Render;
 #endif
                
                //--
@@ -1235,9 +1270,31 @@ public class Page : TemplateControl, IHttpHandler
                }
        }
        
+#if NET_2_0
+       bool CheckForValidationSupport (Control targetControl)
+       {
+               if (targetControl == null)
+                       return false;
+               Type type = targetControl.GetType ();
+               object[] attributes = type.GetCustomAttributes (true);
+               foreach (object attr in attributes)
+                       if (attr is SupportsEventValidationAttribute)
+                               return true;
+               return false;
+       }
+#endif
+       
        void RaisePostBackEvents ()
        {
+#if NET_2_0
+               Control targetControl;
+#endif
                if (requiresRaiseEvent != null) {
+#if NET_2_0
+                       targetControl = requiresRaiseEvent as Control;
+                       if (targetControl != null && CheckForValidationSupport (targetControl))
+                               scriptManager.ValidateEvent (targetControl.UniqueID, null);
+#endif
                        RaisePostBackEvent (requiresRaiseEvent, null);
                        return;
                }
@@ -1252,11 +1309,21 @@ public class Page : TemplateControl, IHttpHandler
                        return;
                 }
 
+#if NET_2_0
+               targetControl = FindControl (eventTarget);
+               IPostBackEventHandler target = targetControl as IPostBackEventHandler;
+#else
                IPostBackEventHandler target = FindControl (eventTarget) as IPostBackEventHandler;
+#endif
+                       
                if (target == null)
                        return;
 
                string eventArgument = postdata [postEventArgumentID];
+#if NET_2_0
+               if (CheckForValidationSupport (targetControl))
+                       scriptManager.ValidateEvent (targetControl.UniqueID, eventArgument);
+#endif
                RaisePostBackEvent (target, eventArgument);
        }
 
@@ -1675,11 +1742,14 @@ public class Page : TemplateControl, IHttpHandler
                if (callbackTarget == null || callbackTarget.Length == 0)
                        throw new HttpException ("Callback target not provided.");
 
-               ICallbackEventHandler target = FindControl (callbackTarget) as ICallbackEventHandler;
+               Control targetControl = FindControl (callbackTarget);
+               ICallbackEventHandler target = targetControl as ICallbackEventHandler;
                if (target == null)
                        throw new HttpException (string.Format ("Invalid callback target '{0}'.", callbackTarget));
 
                string callbackArgument = _requestValueCollection [CallbackArgumentID];
+               if (CheckForValidationSupport (targetControl))
+                       scriptManager.ValidateEvent (targetControl.UniqueID, callbackArgument);
                target.RaiseCallbackEvent (callbackArgument);
                return target.GetCallbackResult ();
        }
diff --git a/mcs/class/System.Web/System.Web.UI/PageLifeCycle.cs b/mcs/class/System.Web/System.Web.UI/PageLifeCycle.cs
new file mode 100644 (file)
index 0000000..0dd1779
--- /dev/null
@@ -0,0 +1,48 @@
+//
+// System.Web.Compilation.PageLifeCycle
+//
+// Authors:
+//   Marek Habersack (grendello@gmail.com)
+//
+// (C) 2006 Marek Habersack
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if NET_2_0
+internal enum PageLifeCycle
+{
+       Unknown = 1,
+       Start,
+       PreInit,
+       Init,
+       InitComplete,
+       PreLoad,
+       Load,
+       ControlEvents,
+       LoadComplete,
+       PreRender,
+       SaveStateComplete,
+       Render,
+       Unload,
+       End
+}
+#endif
index d5fbaa9162ca493b85157f5e99a5977915b09793..19aaf99911873897e9ca48bb8edf939a9a57995e 100644 (file)
@@ -45,29 +45,31 @@ namespace System.Web.UI
                private bool performValidation;
                private string validationGroup;
 
-               public PostBackOptions (Control control)
-                       : this (control, null, null, false, false, false, true, false, null)
+               public PostBackOptions (Control targetControl)
+                       : this (targetControl, null, null, false, false, false, true, false, null)
                {
                }
 
-               public PostBackOptions (Control control, string argument)
-                       : this (control, argument, null, false, false, false, true, false, null)
+               public PostBackOptions (Control targetControl, string argument)
+                       : this (targetControl, argument, null, false, false, false, true, false, null)
                {
                }
 
-               public PostBackOptions (Control control, string argument, string actionUrl, bool isAutoPostBack,
-                                       bool isJavaScriptProtocolRequired, bool isTrackFocus, bool isClientSubmit,
-                                       bool isValidationPerformed, string validatingGroup)
+               public PostBackOptions (Control targetControl, string argument, string actionUrl, bool autoPostBack,
+                                       bool requiresJavaScriptProtocol, bool trackFocus, bool clientSubmit,
+                                       bool performValidation, string validationGroup)
                {
-                       this.control = control;
+                       if (targetControl == null)
+                               throw new ArgumentNullException ("targetControl");
+                       this.control = targetControl;
                        this.argument = argument;
                        this.actionUrl = actionUrl;
-                       this.autoPostBack = isAutoPostBack;
-                       this.requiresJavaScriptProtocol = isJavaScriptProtocolRequired;
-                       this.trackFocus = isTrackFocus;
-                       this.clientSubmit = isClientSubmit;
-                       this.performValidation = isValidationPerformed;
-                       this.validationGroup = validatingGroup;
+                       this.autoPostBack = autoPostBack;
+                       this.requiresJavaScriptProtocol = requiresJavaScriptProtocol;
+                       this.trackFocus = trackFocus;
+                       this.clientSubmit = clientSubmit;
+                       this.performValidation = performValidation;
+                       this.validationGroup = validationGroup;
                }
 
                [DefaultValue ("")]
index c262bbb78326c8b16fae0319a5c956c847863cee..bd93872786ed54c949c841296e75585c6a211d17 100644 (file)
@@ -589,6 +589,7 @@ System.Web.UI/OutputCacheLocation.cs
 System.Web.UI/OutputCacheParameters.cs
 System.Web.UI/Page.cs
 System.Web.UI/PageHandlerFactory.cs
+System.Web.UI/PageLifeCycle.cs
 System.Web.UI/PageParser.cs
 System.Web.UI/PageStatePersister.cs
 System.Web.UI/PageTheme.cs