You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There is a thread safety issue when using Mock instances in a multi-threaded environment.
Here is the exception that I get occasionally when using an instance of a generic Mock class for my IProcessingKey interface (created using the default Mock constructor) and trying to get a value of Id property which is defined in my IProcessingKey interface, which is of a reference type and which has not been explicitly setup (default value is expected to be used):
System.ArgumentException: An item with the same key has already been added.: at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at Moq.MockDefaultValueProvider.ProvideDefault(MethodInfo member)
at Moq.HandleMockRecursion.HandleIntercept(ICallContext invocation, InterceptorContext ctx, CurrentInterceptContext localctx)
at Moq.Interceptor.Intercept(ICallContext invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.IProcessingKeyProxy.get_Id()
at [ … skipping my own production code … ]
Moq version used: 4.2.1507.118 (obtained from NuGet)
The problem seems to be caused by a race condition in ProvideDefault method of MockDefaultValueProvider class where Mock.InnerMocks dictionary is used in a not thread-safe manner. When two different threads call that method concurrently for the same instance of MockDefaultValueProvider, there is a good chance that Mock.InnerMocks.TryGetValue would return false for both of them and they both would try to add the same entry twice to the dictionary (which would cause an exception like the one shown above).
A solution for this problem could be using a lock covering the operations performed on the dictionary (TryGetValue and Add) or using System.Collections.Concurrent.ConcurrentDictionary class as the type for Mock.InnerMocks propety (instead of the common Dictionary class) and use it’s GetOrAdd method for thread-safe checking and updating of the dictionary (instead of calling separate methods TryGetValue and Add).
The text was updated successfully, but these errors were encountered:
…ockDefaultValueProvider)
Fixed issue devlooped#205 with the replacement of Dictionary type with
ConcurrentDictionary for InnerMocks property and using its GetOrAdd
method in MockDefaultValueProvider for making it thread-safe.
There is a thread safety issue when using Mock instances in a multi-threaded environment.
Here is the exception that I get occasionally when using an instance of a generic Mock class for my IProcessingKey interface (created using the default Mock constructor) and trying to get a value of Id property which is defined in my IProcessingKey interface, which is of a reference type and which has not been explicitly setup (default value is expected to be used):
Moq version used: 4.2.1507.118 (obtained from NuGet)
The problem seems to be caused by a race condition in ProvideDefault method of MockDefaultValueProvider class where Mock.InnerMocks dictionary is used in a not thread-safe manner. When two different threads call that method concurrently for the same instance of MockDefaultValueProvider, there is a good chance that Mock.InnerMocks.TryGetValue would return false for both of them and they both would try to add the same entry twice to the dictionary (which would cause an exception like the one shown above).
A solution for this problem could be using a lock covering the operations performed on the dictionary (TryGetValue and Add) or using System.Collections.Concurrent.ConcurrentDictionary class as the type for Mock.InnerMocks propety (instead of the common Dictionary class) and use it’s GetOrAdd method for thread-safe checking and updating of the dictionary (instead of calling separate methods TryGetValue and Add).
The text was updated successfully, but these errors were encountered: