InvalidCastException when trying to get string array from ApplicationData
Describe the bug
When building the app with PublishAot=true, getting a string array from ApplicationData.Current.LocalSettings and casting it to the string[] type I get:
System.InvalidCastException: 'Unable to cast object of type 'WinRT.IInspectable' to type 'System.String[]'.'
Steps to reproduce the bug
Set in csproj:
<PublishAot>true</PublishAot>
ApplicationData.Current.LocalSettings.Values["test"] = new string[] { "a", "b", "c" };
var array = (string[])ApplicationData.Current.LocalSettings.Values["test"];
Expected behavior
No crash
Screenshots
NuGet package version
Windows App SDK 1.6.0: 1.6.240829007
Packaging type
Packaged (MSIX)
Windows version
Windows 11 version 22H2 (22621, 2022 Update)
IDE
Visual Studio 2022
Additional context
Example project: Test.zip
I think I met the same/related issue on another example (WASDK v1.6, AOT enabled):
SelectionChangedEventArgs args = new([], []);
Throws invalidcastexception: "specified cast is not valid".
@manodasanW Does this look related to the collection expression marshaling issue?
I'm also seeing crashes when setting an IEnumerable as ItemSource, like this:
comboBox.ItemsSource = Enumerable.Range(0, 10).Select(x => new TestItem(x));
No crash when using .ToList()
comboBox.ItemsSource = Enumerable.Range(0, 10).Select(x => new TestItem(x)).ToList();
If this is a separate issue and you want me to open a new issue, please let me know
Any hope this will be resolved with the next release? It's the only thing blocking me from using NativeAot.
The problem still happens with 1.7.250109001-experimental2
"I'm also seeing crashes when setting an IEnumerable as ItemSource, like this: comboBox.ItemsSource = Enumerable.Range(0, 10).Select(x => new TestItem(x));"
That's expected and not supported. You need either ToList() or ToString().
Can repro with CsWinRT 2.2.0, only if PublishAot is set. Otherwise the cast works (both to string[] and interfaces).
If this helps, we should look into ComWrappersSupport. GetRuntimeClassForTypeCreation and TypeNameSupport. They determine which type the return value is, and it's woefully incomplete for AOT scenarios.
Just ran into something similar using a FlipView with an ObservableCollection<string> as the ItemsSource. The only way to get around it was to set the AllowUnsafeBlocks to true in the csproj - weird.
System.InvalidCastException: 'Unable to cast object of type 'WinRT.IInspectable' to type 'System.String[]'.'
That's expected and by design. If you use CsWinRT 2.2.0 you'll get a proper warning telling you to enable that.
I've reported this issue six months ago. Is there any hope this will get fixed any time soon? It's the only blocker that prevents me using Native AOT for this particular app. Should I just JSON-serialize my string array and write the resulting string to my local app settings? It will be a pain migrating my users, but I don't see any progress here...
@tipa I had to do the json serialize/deserialize workaround as well, not sure how this was overlooked in the first place? Setting a collection as a source is a VERY common routine. People claiming it's "by design" - I don't buy that excuse. I guess the other question becomes How to properly cast a 'System.String[]' to 'WinRT.IInspectable' if the BCL is unable to perform this step natively? Furthermore, dynamic binding would appear to be the root cause due to the performance AOT is claiming?
This is incredibly hard to achieve in AOT because WinRT only provides type information during runtime, but the type itself could have been trimmed due to AOT.
There's no precise way to check what would be cast when, either. Sure, a scenario where you cast immediately within a line might be easily analyzable. However, what if you decide to keep the original type (that is of no use) and decide to later on, in another file, cast it?
@dongle-the-gadget I'm not sure that scenario is common, is it? Typically casting is of the sub/super flavor, e.g. Control to FrameworkElement. At any rate, maybe a reserved keyword should be allocated for such scenarios to help the AOT.
Also, even with AOT disabled it still complains about the WinRT.IInspectable even though it's not relevant anymore. Possibly AOT could just switch to a reflection mode to drop out of the performance mode in these cases.
The IInspectable to string[] in WinRT is a boxing scenario where it makes use of Windows.Foundation.IReferenceArray<string>. This code path currently does have issues on AOT due to lack of static type information from the projection. But there are plans to try to address this similar to how we address Windows.Foundation.IReference<>. At least for primitive types such as this, we should be able to get it to work. I had made an initial attempt, but there were a couple issues which I will try to pick up and get addressed.
Note the by design reference was to needing to have AllowUnsafeBlocks enabled for certain scenarios to work. This is because to enable certain scenarios our source generator generates sources that make use of unsafe which would otherwise not compile if that wasn't enabled.
@manodasanW Thanks, this is the best explanation I've heard so far - I'll definitely check out your IReferenceArray2!
Possibly AOT could just switch to a reflection mode to drop out of the performance mode in these cases.
This is in the hands of the .NET team, who has decided not to offer such an option.
@manodasanW thanks for your response. I see your linked fork was last active in September last year. I am not too familiar with the topic to understand if I can use this code to workaround the problem myself in the meantime or if I need to wait for an official release. After 6 months, I'd like to make a decision now on how to proceed. Is there any chance this bug will be fixed in the next few weeks or (1-2) months? If not, I will have to JSON-serialize my array and save that string (I would like to avoid that since the previously stored string array essentially in the local app settings is "lost" and users fall back to the default)
@manodasanW I spent a considerable amount of time, trying to understand your IReferenceArray2 code and apply it to my problem, but without luck. Unfortunately, I am not familiar with the internals of CsWinRT.
Can you please give a rough timeline when this issue will be fixed - or if it will not be fixed at all?
I am still having this issue and it blocks me from migrating the rest of my apps to WinUI3 - is there any hope this will be fixed? It would be greatly appreciated! :)
@manodasanW @Sergio0694 This happens again with .net10-rc1 - can this issue be reopened? Example project: Test (1).zip
@tipa is this with CsWinRT 2.3.0-prerelease.250720.1?
@manodasanW Yes. This time reproducing it isn't as easy as just running it via the IDE in Release mode, I had to build the package and install it, but the problem is the same, with a slightly different error message: "Specified cast is not valid".
The type of the object that is returned from the application settings is again of type WinRT.IInspectable and GetRuntimeClassName() returns Windows.Foundation.IReferenceArray`1<String>