Reputation: 335
What I want to do: - synchronously (or even asynchronously) load settings from USB drive before first page loads
What I did: - in OnLaunched method for App.xaml.cs I invoked this static function:
public static async void LoadSettings(string folderName = "Config", string fileName = "Settings.xml")
{
try
{
StorageFile configFile = null;
// scan through all devices
foreach (var device in await KnownFolders.RemovableDevices.GetFoldersAsync().AsTask().ConfigureAwait(false))
{
// folder that should have configuration
var configFolder = await device.GetFolderAsync(folderName).AsTask().ConfigureAwait(false);
if (configFile != null && configFolder != null && await configFolder.GetFileAsync(fileName).AsTask().ConfigureAwait(false) != null)
{
throw new Exception("More than one configuration file detected. First found configuration file will be used.");
}
else
configFile = await configFolder.GetFileAsync(fileName).AsTask().ConfigureAwait(false);
}
if (configFile == null)
throw new Exception("Configuration file was not found, please insert device with proper configuration path.");
string settingString = await FileIO.ReadTextAsync(configFile).AsTask().ConfigureAwait(false);
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
using (TextReader reader = new StringReader(settingString))
{
AppSettings = (Settings)serializer.Deserialize(reader); // store settings in some static variable
}
}
catch (Exception e)
{
//return await Task.FromResult<string>(e.Message);
}
//return await Task.FromResult<string>(null);
}
As you can see right now it's async void method, so I don't even want to synchronize it in any way with UI thread. It should just fire and do something. With ConfigureAwait(false) I want to be sure that it will never try to return to context. These returns at the end are remnants of other things I tried (I wanted to do this better way, this is the most primitive solution and it still doesn't work).
Anyway, because that's where the fun begins: everything works well when I debug application on local machine with Win 10. And I get deadlocked thread on Win 10 IOT installed on Raspberry Pi 3 (I installed it from the scratch today, last version).
But deadlock is not the weirdest thing. Weirdest thing is when it appears.
Like I said, invocation of this method looks like that:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Configuration.Settings.LoadSettings();
After that everything in this method goes normally, so I navigate to my first page somewhere below:
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
rootFrame.Navigate(typeof(LogScreen), e.Arguments);
}
Window.Current.Activate();
}
Everything still works. User needs to write his code, I check if this code is available in settings and after that user can press "OK" to move to next page. Somewhere in LogScreenViewModel this method is responsible for that:
private void GoForward(bool isValid)
{
try
{
_navigationService.NavigateTo("MainPage"); // it's SimpleIoc navigation from MVVMLight
}
catch (Exception e)
{
Debug.WriteLine($"ERROR: {e.Message}");
}
}
And deadlock happens when _navigationService.NavigateTo("MainPage") is reached. Basically right now UI thread freezes. If I wait for long enough I will see catched exception in Output saying that messenger seemed occupied (I can't show the screen because I don't have access to that Raspberry right now) and after some timeout this thread was killed (like 30 seconds or something) - after that UI thread unlocks and application proceeds to MainPage. It doesn't happen on PC - MainPage appears immediately, no exceptions, no deadlocks.
I tried waiting on first page for like 1 minute to check if some deadlock exception would fire on it's own - but it doesn't. It will fire ONLY after I try to proceed to next page.
What else I tried instead of this fire-and-forget approach:
Window.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => await Configuration.Settings.LoadSettings(); ).AsTask().Wait();
If I remember correctly it deadlocked immediately on Wait(), even with ConfigureAwait(false) everywhere, but it also happened on PC.What am I missing? What else can I try? Because to be honest right now it looks to me that Win 10 IOT .NET runtime is bugged or something.
Upvotes: 0
Views: 235
Reputation: 335
I think I resolved the issue. This code was generally speaking not mine and after some digging I noticed that someone before me tried to list some other external devices while navigating to MainPage. It was not really async-safe code (someone probably wasn't aware of synchronization context) and it worked on Win 10 only because on desktop it was looking for COM0 device and I only have COM2, so method causing trouble was not even invoked at all.
I still have no idea how related it was to my configuration (because it somehow was working without it), but after I fixed issues with this old not-async-safe code it started to behave as expected.
Upvotes: 0