I have been reviewing the AjaxControlToolkit build 10301 for possible inclusion in our product.
As a result I may have spotted a minor thread safety bug in ScriptObjectBuilder.
It concerns access to the generic Dictionary based static data members _cache and _cssCache.
In the methods
private static List<ResourceEntry> GetScriptReferencesInternal(Type type, Stack<Type> typeReferenceStack)
and
private static IEnumerable<string> GetCssReferences(Control control, Type type, Stack<Type> typeReferenceStack)
the following type of code is used to access the static data members.
// Look for a cached set of references outside of the lock for perf.
//
List<ResourceEntry> entries;
if (_cache.TryGetValue(type, out entries))
{
return entries;
}
The code is performed outside the lock (_sync) statements and consequently is not thread safe because the generic dictionary is not thread safe (see the .Net 2.0 docs + code review with reflector).
You could change the implementation to use the old fashioned typeless System.Collections.Hashtable.
Microsoft re-engineered Hashtable in .Net 2.0 to be thread safe to multiple readers, single writer so your code access pattern would be OK.
The change to Hashtable was made to make ResourceManager more performant in .Net 2.0 which depends on Hashtable for its implementation.
Unfortunately Dictionary<K,V> did not get the Hashtable treatment and consequently it's implementation is not thread safe.
In our own implementations we have a set of singleton cache generics that use Hashtable as the internal implementation so that we get the no lock performance improvement for readers.
I know you lose the value symantics of the generic dictionary, but as long as your key and value are reference types there isn't really a problem (otherwise you get excessive boxing).
Hope this is helpful.
Comments: This ticket was filed for a pre-15.1 version of AJAX Control Toolkit. If this is still an issue in v15.1 or later, please create a new inquiry.
As a result I may have spotted a minor thread safety bug in ScriptObjectBuilder.
It concerns access to the generic Dictionary based static data members _cache and _cssCache.
In the methods
private static List<ResourceEntry> GetScriptReferencesInternal(Type type, Stack<Type> typeReferenceStack)
and
private static IEnumerable<string> GetCssReferences(Control control, Type type, Stack<Type> typeReferenceStack)
the following type of code is used to access the static data members.
// Look for a cached set of references outside of the lock for perf.
//
List<ResourceEntry> entries;
if (_cache.TryGetValue(type, out entries))
{
return entries;
}
The code is performed outside the lock (_sync) statements and consequently is not thread safe because the generic dictionary is not thread safe (see the .Net 2.0 docs + code review with reflector).
You could change the implementation to use the old fashioned typeless System.Collections.Hashtable.
Microsoft re-engineered Hashtable in .Net 2.0 to be thread safe to multiple readers, single writer so your code access pattern would be OK.
The change to Hashtable was made to make ResourceManager more performant in .Net 2.0 which depends on Hashtable for its implementation.
Unfortunately Dictionary<K,V> did not get the Hashtable treatment and consequently it's implementation is not thread safe.
In our own implementations we have a set of singleton cache generics that use Hashtable as the internal implementation so that we get the no lock performance improvement for readers.
I know you lose the value symantics of the generic dictionary, but as long as your key and value are reference types there isn't really a problem (otherwise you get excessive boxing).
Hope this is helpful.
Comments: This ticket was filed for a pre-15.1 version of AJAX Control Toolkit. If this is still an issue in v15.1 or later, please create a new inquiry.