Threading errors with Application.LoadComponent (key already exists)

c#, multithreading, thread-safety, wpf

Solution

You are not doing something wrong. MSDN is wrong. Application.LoadComponent is not actually thread safe. This is a bug in WPF, in my opinion.

The problem is that whenever Application.LoadComponent loads a "Part" from a "Package" it:

- Checks its internal cache for the package to see if the part is already loaded & returns it if found

- Loads the part from the file

- Adds it to the internal cache

- Returns it

You have two threads calling `Application.LoadComponent` to load the same part at the same time. The MSDN documentation says this is ok, but what is happening is:

- Thread #1 checks the cache and starts loading from the file

- Thread #2 checks the cache and starts loading from the file

- Thread #1 finishes loading from the file and adds to the cache

- Thread #2 finishes loading from the file and tries to add to the cache, resulting in a duplicate key exception

The workaround for the bug is to wrap all calls to Application.LoadComponent inside a lock().

Your lock object can be created thusly in your App.cs or elsewhere (your choice):

 public static object MyLoadComponentLock = new Object();

Then your LoadComponent call looks like this:

 lock(App.MyLoadComponentLock)
   genericDictionary = (ResourceDictionary)Application.LoadComponent(...

Problem

MSDN says that public static members of System.Windows.Application are thread safe. But when I try to run my app with multiple threads I get the following exception: ``` ArgumentException: An entry with the same key already exists. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.SortedList`2.Add(TKey key, TValue value) at System.IO.Packaging.Package.AddIfNoPrefixCollisionDetected(ValidatedPartUri partUri, PackagePart part) at System.IO.Packaging.Package.GetPartHelper(Uri partUri) at System.IO.Packaging.Package.GetPart(Uri partUri) at System.Windows.Application.GetResourceOrContentPart(Uri uri) at System.Windows.Application.LoadComponent(Uri resourceLocator, Boolean bSkipJournaledProperties) at System.Windows.Application.LoadComponent(Uri resourceLocator) ``` The exception occurs on the following call: ``` genericResources = (ResourceDictionary)Application.LoadComponent(new Uri("/Themes/Generic.xaml", UriKind.Relative)); ``` The application works fine on a single thread and even on two or three. When I get up past 5 then I get the error every time. Am I doing something wrong? What can I do to fix this?

Original source