Problem description:
Necessary conditions:
phenomenon:
聽- An exception is thrown and the application crashes
Actual behavior:
```
Exception thrown: 'System.NullReferenceException' in WindowsBase.dll
Object reference not set to an instance of an object.
System.NullReferenceException: Object reference not set to an instance of an object.
at System.IO.Packaging.PackagePart.CleanUpRequestedStreamsList()
at System.IO.Packaging.PackagePart.GetStream(FileMode mode, FileAccess access)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at Walterlv.Bugs.MultiThreadedUI.SplashWindow.InitializeComponent() in C:\Users\lvyi\Desktop\Walterlv.Bugs.MultiThreadedUI\Walterlv.Bugs.MultiThreadedUI\SplashWindow.xaml:line 1
at Walterlv.Bugs.MultiThreadedUI.SplashWindow..ctor() in C:\Users\lvyi\Desktop\Walterlv.Bugs.MultiThreadedUI\Walterlv.Bugs.MultiThreadedUI\SplashWindow.xaml.cs:line 24
at Walterlv.Bugs.MultiThreadedUI.Program.<>c__DisplayClass1_0.

**Expected behavior:**
Don't crash.
**Minimal repro:**
1. Create a new WPF project (either .NET Core 3 or .NET Framework 4.8)
2. Keep the automatically generated `App` and `MainWindow` unchanged, we create a new window `SplashWindow`.
3. Create a new `Program` class containing the Main function and set `Program` as the startup object (instead of `App`) in the project properties.

All other files remain the same as the default code generated by Visual Studio, and the code of Program.cs is as follows:
```csharp
using System;
using System.Threading;
using System.Windows.Threading;
namespace Walterlv.Bugs.MultiThreadedUI
{
public class Program
{
[STAThread]
private static void Main(string[] args)
{
for (var i = 0; i < 50; i++)
{
RunSplashWindow(i);
}
var app = new App();
app.InitializeComponent();
app.Run();
}
private static void RunSplashWindow(int index)
{
var thread = new Thread(() =>
{
var window = new SplashWindow
{
Title = $"SplashWindow {index.ToString().PadLeft(2, ' ')}",
};
window.Show();
Dispatcher.Run();
})
{
IsBackground = true,
};
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
}
}
Remarks: Even if you add this code just before the Splash Window creating, this exception still occurs.
SynchronizationContext.SetSynchronizationContext(
new DispatcherSynchronizationContext(
Dispatcher.CurrentDispatcher));
The null object may be _requestedStreams and this is the code that set it to null:
The same issue can be seen here:
Because I can't find out why this bug happens, so I just post the issue itself.
Thanks for filing this issue @walterlv. This item and #298 seem very similar, is the reason you opened a separate issue because the crashes have different callstacks?
@stevenbrix The two issues have something differences:
If it's recommended to merge these two issues, I'll do that.
Thanks @walterlv. I just wanted to make sure that the repos and symptoms were indeed different. I think we should keep these two separate considering they will have separate fixes.
@stevenbrix I've posted the code to GitHub:
The Walterlv.Bugs.MultiThreadedUI is the .NET Framework version and the Walterlv.Bugs.MultiThreadedUI.Core is the .NET Core version.
We're also running into this behavior with our .NET Framework 4.7.2 app. In our case, we start up another thread to render reports on, and will sometimes get the NullReferenceException mentioned here, and other times get a IndexOutOfRangeException in PackagePart.CleanUpRequestedStreamsList(). It seems that the multiple threads wind up working on the same PackagePart.
I also encountered such a problem. How did you solve it
I also encountered such a problem. How did you solve it
The root cause is apparently a race condition within the automatically generated InitializeComponent() method.
So the way I've worked around this is to call InitializeComponent() within a lock on a static singleton. For example:
public partial class YourUserControl
{
static readonly object Gate = new object();
public YourUserControl()
{
lock (Gate)
InitializeComponent();
}
}
Note: you can add code-behind for ResourceDictionarys too. The code-behind gives you a place to add the lock statement if needed:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
x:Class="Your.ResourceDictionary.Class.Here">
...
I've used the above in production code to work around this issue. Perhaps one would be able to find a more elegant solution by studying the source code behind the offending framework call to System.IO.Packaging.PackagePart.CleanUpRequestedStreamsList(), but I don't like spending my time trying to work around decades-old Microsoft bugs so I did the above and moved on.
Most helpful comment
The root cause is apparently a race condition within the automatically generated
InitializeComponent()method.So the way I've worked around this is to call
InitializeComponent()within a lock on a static singleton. For example:Note: you can add code-behind for
ResourceDictionarys too. The code-behind gives you a place to add thelockstatement if needed:I've used the above in production code to work around this issue. Perhaps one would be able to find a more elegant solution by studying the source code behind the offending framework call to
System.IO.Packaging.PackagePart.CleanUpRequestedStreamsList(), but I don't like spending my time trying to work around decades-old Microsoft bugs so I did the above and moved on.