Reputation: 2609
I can't figure out how threads of different types behave in UWP applications. First, in UWP it seems that UI thread is not a main thread, it's one of worker threads (I see this in the debugger when inserting breakpoints in event handlers and so on). My assumption is that CoreApplication.MainView.CoreWindow.Dispatcher.HasThreadAccess
designates if the current thread a UI thread or not.
From my understanding some actions should behave differently depending on the type of the current thread. In particular, synchronous I/O methods should raise an exception that synchronous I/O is not allowed on UI thread.
For instance, File.Exists, File.Move or creating a file with FileStream constructor. I even actually got these exceptions earlier but now can't figure out how to reproduce them again. They all are mysteriously gone. Even if I put these methods directly in a button.Click handler (which executes on UI thread, I believe, HasThreadAccess
is true), they still work.
I believe this code kept throwing InvalidOperationException back in 2016 Dec when I tested it last time:
private async void button_Click(object sender, RoutedEventArgs e)
{
if (File.Exists(Path.Combine(ApplicationData.Current.LocalFolder.Path, "log.txt")))
{
}
Or, maybe, the code was close but not equal to that, maybe I'm missing some important detail..
I need to find a way to make these exceptions reliably occur again so that I could correctly refactor the old synchronous library to async and test it thoroughly. Without exceptions being thrown, I can't actually be sure that on someone's else system this library won't crash due to these I/O threading issues.
Upvotes: 2
Views: 432
Reputation: 2609
Got it. For some weird reason, synchronous methods of System.IO namespace behave differently (in terms of threading) for disk folders in different locations.
This works:
FileStream fs = new FileStream(Path.Combine(ApplicationData.Current.LocalFolder.Path, "log.txt"), FileMode.OpenOrCreate);
The below crashes with 'System.InvalidOperationException' and message 'Synchronous operations should not be performed on the UI thread. Consider wrapping this method in Task.Run':
FileStream fs = new FileStream(@"C:\Temp\log.txt", FileMode.OpenOrCreate);
At the same time, if I run the latter on a worker thread rather than UI thread, I get accurate UnauthorizedAccessException telling me that Access is denied.
I.e. it seems that prohibition to run synchronous operations on UI thread does NOT concern folders (at least ApplicationData.Current.LocalFolder) where this I/O is allowed and does concern folders where this I/O is not allowed anyway. Maybe a bug in .NET code for UWP that wrong exception is thrown?
That's strange as I believe it should be no relation between threading and access control matters but at least I found a way to make UWP sync method crash in the way I needed.
EDIT:
Turns out it's the correct and expected behavior. When on UI thread, WinRT won't even try to access resources outside LocalFolder because it would cause internal deadlock (that's just how WinRT works under the hood). For LocalFolder access, using UI thread for sync I/O is allowed. That's why I'm getting InvalidOperationException (rather than UnauthorizedAccessException) on UI thread only when accessing resources outside LocalFolder.
The problem with UI thread will be with an object like file picker which can return location outside of LocalFolder (brokered file). Accessing such file on a worker thread won't throw UnauthorizedAccessException and will go just fine but on a UI thread we'll get InvalidOperationException because the file is outside LocalFolder. So, brokered files can only be accessed from a worker thread (either via natively async methods or via sync methods on a dedicated worker thread).
Upvotes: 2