I'm working on a Windows Service that cycles through a series of databases and then sends SMS messages using HTTP requests. In the beginning of the method that goes through each database, I define a generic list as follows:
public static List<Recipient> Recipients = new List<Recipient>();
I populate that list with the results of an asynchronous HTTP request sent through a thread pool:
//inside main method
foreach (var SMS in SMSJoin)
{
...
SMSMessage oSMS = new SMSMessage(Keyword, Number, Message, MessageID);
ThreadPool.QueueUserWorkItem(SendSMS, oSMS);
}
Then it gets passed to the next method:
public static void SendSMS(object SMStoSend)
{
try
{
SMSMessage oSMS = (SMSMessage)SMStoSend;
...
Request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), state);
}
...
}
Then to GetRequestStreamCallback
...
public static void GetRequestStreamCallback(IAsyncResult AsynchronousResult)
{
State state = (State)AsynchronousResult.AsyncState;
SMSMessage oSMS = state.oSMS;
try
{
...
Request.BeginGetResponse(new AsyncCallback(ReceiveResponse), state);
}
...
}
And finally the response is received and added to the Recipients List:
public static void ReceiveResponse(IAsyncResult Result)
{
...
finally
{
oSMS.Complete = DateTime.Now;
Recipient CompleteMessage = new Recipient(oSMS.MessageID, oSMS.Recipient, oSMS.ErrorCode, oSMS.Complete, oSMS.ResponseCode);
Recipients.Add(CompleteMessage);
}
At the end of the code, each response should be added to a Recipient
object and then stored in the generic list. The problem is that once about every 1000 or so SMS messages (sent in batches of 50), there is an unhandled IndexOutOfRangeException
thrown by the line of code Recipients.Add(CompleteMessage)
.
I didn't think that there were indexes in the list, and many of the recipients are duplicates. Why would it throw this error, and why only every once in a good while? Could this have to do with threading issues?
As a note, I'm activating the main method from a Timer
object, but it will wait until the previous instance is complete before starting a new instance.
Edit:
Here is the Recipient
class:
public class Recipient
{
public Recipient(long MessageID, string PhoneNumber, string ErrorMessage, DateTime? Completed, string Response)
{
this.MessageID = MessageID;
this.PhoneNumber = PhoneNumber;
this.ErrorMessage = ErrorMessage;
this.Completed = Completed;
this.Response = Response;
}
public long MessageID { get; set; }
public string PhoneNumber { get; set; }
public string ErrorMessage { get; set; }
public DateTime? Completed { get; set; }
public string Response { get; set; }
}