X
    Categories: General

System.ArgumentOutOfRangeException occurs when updating DataView object

I have been working on a project which involves sending out emails to our customers in the past week and came across a very interesting error with a DataView object.

The application is required to send out batch emails once a day, so I created an email message queue table to store the outgoing email messages. After a message is sent, the column that stores the delivery status will be changed from 0 to1 so that the next time the application will skip the record. Simple enough. Here are the steps:

Loads the records in the email message queue table within a given date range into a DataTable object dt.

Creates a DataView object out of the DataTable with RowsFilter=”Sent=0″:

Dim dv As DataView = New DataView(dt)
dv.RowsFilter = "Sent=0"

Loops through the DataView object, sends out emails, update the delivery status to Sent=1.

For i As Integer = 0 To dv.Count - 1
   ' Send out the email
   ' Update the record
   dv.Item(i)("Sent") = True
   ' Update the database
Next

Looks very logical, right? But I got a System.ArgumentOutOfRangeException error on the loop. After a couple hours of investigation, I finally found the cause of the exception.

It turned out that the exception error only happens when I update the value of the column on which I set my filter, but no error is encountered if I change the values of other columns:

dv.Item(i)("SentDate") = DateTime.Now  ' No error

dv.Item(i)("SentBy") = username         ' No error

dv.Item(i)("Sent") = True               ' Error!!

When stepping through the code, an interesting thing shows up. After the execution of the line

dv.Item(i)("Sent") = True

the total number of records in the DataView object is decreased by 1 automatically. It seems that the data in the DataView object does not remain static, and some underlying event handler is called to re-apply the filter criteria and to return a new total count. Therefore, when the loop reaches the end of the DataView object, the index i is already greater than the total count and the ArgumentOutOfRangeException is thrown.

I am not sure if it is designed this way, or it is related to this known bug: http://support.microsoft.com/default.aspx?scid=kb;en-us;836874

Workaround:

Replace the For loop with a While loop:

While dvEmails.Count <> 0
  Dim i As Integer = 0
  ' Send email
  ' Update the record
  dvEmails.Item(i)("SentDate") = DateTime.Now.ToString
  dvEmails.Item(i)("IsSent") = True
  emailQueue.Save()
End While

Jeffrey:
Related Post