Monday, September 25, 2017

User clicks during a GridView.DataBind call causes ArgumentException

Leave a Comment

I have read a lot about the popular Invalid postback or callback argument error message.

I get this error if I rush the web page by clicking on any type of link/redirect (in this case an ASP LinkButton, but the same result occurs when using an ASP Button) before a web page GridView has finished data binding.

The data being bound is very large and, ideally, I should add paging to make it execute faster. However, besides the click, there is no additional data being modified, including any client scripts, so I am unsure why this error is occurring.

Full error:

Invalid postback or callback argument. Event validation is enabled using 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.

I don't want to disable event validation for security reasons and I know that the large DataBind operation is the reason for this but I don't know why.

I have also tried disabling the grid validation as a simple test but this did not solve the issue:

myGrid.ValidateRequestMode = ValidateRequestMode.Disabled 

The LinkButton is not using PostBackUrl and is instead using a Click event + Response.Redirect (I removed all irrelevant code).

The LinkButton is also created before the DataBind takes place.

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load      Dim application As IApplication      If Not IsPostBack Then          application = Session("App")                       If application IsNot Nothing Then              AddLinkButton("Test", "EntityPage", CommandType.PageLink)             ShowData(application)                              End If      End If  End Sub  Private Sub AddLinkButton(label As String, commandArgument As String,                          Optional command As CommandType = CommandType.Link)      Dim linkBtn As New LinkButton()             linkBtn.Text = label     linkBtn.CssClass = "myLinkBtn"     linkBtn.CommandName = command.ToString     linkBtn.CommandArgument = commandArgument      AddHandler linkBtn.Click, AddressOf LinkButton_Click      panel.Controls.Add(linkBtn) End Sub   Private Sub LinkButton_Click(ByVal sender As Object, ByVal e As EventArgs)      Dim linkBtn As LinkButton = CType(sender, LinkButton)      Select linkBtn.CommandName          Case "Link" :              Response.Redirect(linkBtn.CommandArgument, False)          ' more cases + additional logic that I removed from the example      End Select  End Sub  Friend Sub ShowData(application As IApplication)      Dim entities As List(Of Entity)      If Not IsPostBack Then          entities = application.GetEntities()          myGridView.DataSource = entities         myGridView.DataBind()      End If  End Sub 

Why do you think this is happening? And is there any way to possibly interrupt the data bind successfully?

EDIT: Also tried using Button instead of LinkButton, and using UseSubmitBehavior = True, but same result.

2 Answers

Answers 1

I think this error is not because of large amount of data in GridView. This will Validates PostBack is from correct path/source which will be gone by setting EnableEventValidation="false" in your page.


As you won't set EnableEventValidation="false" then you can do something like this:

  • Place your GridView inside an UpdatePanel control and do asp:AsyncPostBackTrigger trigger for your GridView.

    <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">   <ContentTemplate>       <asp:GridView ID="GridView1" runat="server"OnRowCommand="GridView1_RowCommand">      </asp:GridView> </ContentTemplate>  <Triggers>     <asp:AsyncPostBackTrigger  ControlID="GridView1" /> </Triggers>  </asp:UpdatePanel> 
  • In your GridView add RowCommand event and place your LinkButton/Button code there, by checking correct e.CommandName == "LinkButtonCommandName" and find your GridViewRow for other working.

    Protected Sub GridView1_RowCommand(ByVal sender As Object, ByVal e As GridViewCommandEventArgs)     Dim index As Integer = Convert.ToInt32(e.CommandArgument)     Dim gvRow As GridViewRow = GridView1.Rows(index) // find GridView clicked row     // find LinkButton from GridView row     Dim LinkButton1 As LinkButton = CType(GridViewRow.FindControl("LinkButton1"), LinkButton)     //... here some logic End Sub 

Answers 2

You are on the wrong track: there is nothing wrong with your data nor its volume. What's wrong is this:

The LinkButton is also created before the DataBind takes place.

This is simply not enough. You need to create dynamic controls (such as your LinkButton) earlier in the page life cycle, because ASP.NET must do its magic and setup the ViewState for the dynamic controls too. Note that creation of the ViewState occurs earlier in the lifecycle than the Load event. As stated on the MSDN, the PreInit event is the right place to create or re-create dynamic controls. So you gonna need to get rid of the AddLinkButon sub and add the following within your code behind file:

Private linkBtn As LinkButton ' Declare the LinkButton variable at a module level  Protected Sub Page_PreInit(ByVal sender As Object, ByVal e As EventArgs) Handles Me.PreInit     linkBtn = New LinkButton()             linkBtn.Text = "Test"     linkBtn.CssClass = "myLinkBtn"     linkBtn.CommandName = CommandType.PageLink.ToString     linkBtn.CommandArgument = "EntityPage"      AddHandler linkBtn.Click, AddressOf LinkButton_Click End Sub  Protected Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Init     ' During Init all the controls have been created.     ' During the PreInit event the "panel" control is unavailable.     panel.Controls.Add(linkBtn) End Sub 

And modify the load handler:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load     Dim application As IApplication      If Not IsPostBack Then             application = Session("App")                      linkBtn.Visible = application IsNot Nothing          If linkBtn.Visible Then             ' Remove that next line             ' AddLinkButton("Test", "EntityPage", CommandType.PageLink)             ShowData(application)         End If     End If End Sub 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment