I have a strange behaviour in one of my base methods of an ASP.net web service. First of all: this is code which is productive since years, there has not been reported any problems with it so far. But in my unit tests I recognized two times this problem, so I am confused now, if it is only in my development or if it is a real problem.
Here is my code snippet, where the error
System.ArgumentException: Item has already been added. Key in dictionary: '6' Key being added: '6'
occured when _messages.Add
is called:
public Message Add(GatewayMessageTypes type, string strMessage, CultureInfo language)
{
var message = new Message(type, strMessage, language);
int intCount = _messages.Count + 1;
if (_messages.ContainsKey(intCount))
{
_messages.Remove(intCount);
}
_messages.Add(intCount, message);
return message;
}
_messages
is defined as:
public class MessageHandler
{
private readonly Hashtable _messages = new Hashtable();
And this MessageHandler is used in all my Web Services defined in a base class
public abstract class ServiceBase
{
public MessageHandler MessageHandler { get; protected set; }
This is the StackTrace:
at System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add)
at System.Collections.Hashtable.Add(Object key, Object value)
at GISGatewayCore.MessageHandler.Add(GatewayMessageTypes strType, String strMessage, CultureInfo language) in GISGateway\GISGatewayCore\MessageHandler.cs:line 69
at GISGatewayCore.MessageHandler.AddAndLog(GatewayMessageTypes type, String strMessage, CultureInfo language) in GISGateway\GISGatewayCore\MessageHandler.cs:line 81
at GISGateway.Services.GetClosestFacilityServices.<>c__DisplayClass4.<GetClosestFacilities>b__1(Object index) in GISGateway\GISGateway.Services\GetClosestFacilityServices.cs:line 592
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart(Object obj)
It is right, there are already 6 entries in the collection, and number 6 looks exactly like the new message which should be added. So what is the problem?
I understand your point, it should run synchronously. However, try this and see if it works:
public Message Add(GatewayMessageTypes type, string strMessage, CultureInfo language)
{
lock(_messages)
{
var message = new Message(type, strMessage, language);
int intCount = _messages.Count + 1;
if (_messages.ContainsKey(intCount))
{
_messages.Remove(intCount);
}
_messages.Add(intCount, message);
return message;
}
}
I may being called from two sources on the same "session", like ajax calls on a controller.