Share via


Fix for Exception Reading Typed Headers

This week I'll be running a series covering fixes for WCF that may be hard to find and explaining the details behind each problem.

The dispatch operation formatter is the component that deserializes a message into objects. When building the objects out of the message headers in the message, the implementation of the operation formatters for XmlSerializer and DataContractSerializer uses an internal class called TypedHeaderManager. A TypedHeaderManager is created for each seen content type and then cached to make the object creation process faster in the future.

The cache for TypedHeaderManager objects uses a reader-writer lock to improve concurrency. After the first few messages it should be increasingly rare to need to add items to the cache, making most accesses be reads rather than writes. The cache is first tested under the reader lock for an instance of TypedHeaderManager. The writer lock is acquired if an instance didn't exist for the seen content type to add the entry.

The original code didn't check whether some other thread created a TypedHeaderManager instance for the same type while the writer lock was being acquired. This can happen if multiple messages using a particular header type for the first time arrive at nearly the same time. You're encountering this problem if you see the following exception.

 System.ArgumentException: An item with the same key has already been added.
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at System.ServiceModel.TypedHeaderManager.GetTypedHeaderManager(Type t)

This is an example where double-checked locking was intended but implemented incorrectly.

A fix for this problem was in the Application Compatibility Update for .Net 3.5 Service Pack 1.