Combination of `PublishSingleFile` and `PublishReadyToRun` prevents app from starting
See original GitHub issueProblem description
Since changing the TargetFramework
in our .csproj file from net6.0-windows
to net7.0-windows
our app crashes upon starting with a System.TypeInitializationException
thrown in the initializer for System.Windows.Media.FontFamily
.
Removing either the PublishSingleFile
or the PublishReadyToRun
tag from the projects .csproj file (or switching back to net6.0-windows
) fixes the problem.
Stack-trace
System.TypeInitializationException: The type initializer for 'System.Windows.Media.FontFamily' threw an exception.
---> System.TypeInitializationException: The type initializer for 'MS.Internal.FontCache.DWriteFactory' threw an exception.
---> System.InvalidCastException: Specified cast is not valid.
at MS.Internal.Text.TextInterface.Native.Util.ConvertHresultToException(Int32 hr)
at MS.Internal.Text.TextInterface.Factory.Initialize(FactoryType factoryType)
at MS.Internal.Text.TextInterface.Factory..ctor(FactoryType factoryType, IFontSourceCollectionFactory fontSourceCollectionFactory, IFontSourceFactory fontSourceFactory)
at MS.Internal.FontCache.DWriteFactory..cctor()
--- End of inner exception stack trace ---
at MS.Internal.FontCache.DWriteFactory.get_SystemFontCollection()
at System.Windows.Media.FontFamily..cctor()
--- End of inner exception stack trace ---
at MS.Internal.Text.DynamicPropertyReader.GetTypeface(DependencyObject element)
at MS.Internal.Text.TextProperties.InitCommon(DependencyObject target)
at MS.Internal.Text.TextProperties..ctor(FrameworkElement target, Boolean isTypographyDefaultValue)
at System.Windows.Controls.TextBoxView.GetLineProperties()
at System.Windows.Controls.TextBoxView.TextCache..ctor(TextBoxView owner)
at System.Windows.Controls.TextBoxView.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
at System.Windows.Controls.ScrollContentPresenter.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV, Boolean& hasDesiredSizeUChanged)
at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.ScrollViewer.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Border.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Control.MeasureOverride(Size constraint)
at System.Windows.Controls.TextBox.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Decorator.MeasureOverride(Size constraint)
at System.Windows.Documents.AdornerDecorator.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Border.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Window.MeasureOverrideHelper(Size constraint)
at System.Windows.Window.MeasureOverride(Size availableSize)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Interop.HwndSource.SetLayoutSize()
at System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value)
at System.Windows.Window.SetRootVisualAndUpdateSTC()
at System.Windows.Window.SetupInitialState(Double requestedTop, Double requestedLeft, Double requestedWidth, Double requestedHeight)
at System.Windows.Window.CreateSourceWindow(Boolean duringShow)
at System.Windows.Window.ShowHelper(Object booleanBox)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at MyProject.App.Main()
Expected behavior
The app starts the same way it did when using net6.0-windows
as TargetFramework
.
net48
No idea whether this also reproduces in .NET Framework 4.8. We’re using net7.0
exclusively.
Relation to Visual Studio (or other tooling)
None. We did our testing using the dotnet publish
command.
dotnet info:
.NET SDK:
Version: 7.0.100
Commit: e12b7af219
Runtime Environment:
OS Name: Windows
OS Version: 10.0.19044
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\7.0.100\
...
Environment variables:
Not set
global.json file:
Not found
Minimal reproduction
There are no Directory.Build.props
or Directory.Packages.props
files present.
Executing the project results in a file named ex.txt
with the stack-trace being left in the execution directory.
Project.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0-windows</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<OutputType>WinExe</OutputType>
<UseWPF>true</UseWPF>
</PropertyGroup>
<PropertyGroup>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
</Project>
App.xaml
<Application x:Class="MyProject.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="TestView.xaml"/>
App.xaml.cs
using System;
using System.IO;
using System.Windows;
namespace MyProject;
public sealed partial class App
{
protected override void OnStartup(StartupEventArgs e)
{
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
base.OnStartup(e);
}
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
ArgumentNullException.ThrowIfNull(e);
ArgumentNullException.ThrowIfNull(e.ExceptionObject);
Exception exception = (Exception)e.ExceptionObject;
File.WriteAllText("ex.txt", exception.ToString());
Environment.Exit(byte.MaxValue);
}
}
TestView.xaml
<Window x:Class="MyProject.TestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d">
<Grid>
<TextBox Text="Test"/>
</Grid>
</Window>
TestView.xaml.cs
namespace MyProject;
public partial class TestView
{
public TestView() => InitializeComponent();
}
special thanks to @beagle1986 for lending me his ear.
Issue Analytics
- State:
- Created 10 months ago
- Reactions:10
- Comments:11 (2 by maintainers)
Top GitHub Comments
@Mathyn I believe this issue is being tracked in dotnet/runtime#65879. Starting with .Net 7.0, R2R uses Composite mode by default when also using Single-file (See dotnet/sdk#25963).
As a workaround, you can disable Composite mode by adding this to your csproj:
@dragnilar No. There are no fancy things. The bug can be reproduced with a default WPF app with a TextBlock on the MainWindow.