-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove the use of context within IAsyncOperation to fire handlers. #1131
Conversation
Is there an easy way to test this in a WinAppSdk project without waiting for a new release? (Perhaps by adding a reference to a nightly CsWinRt build?) I have some projects that hang when providing streams as web resources, regardless of the thread apartment model. |
@mqudsi The fix is in the Windows SDK projection generated using CsWinRT. We are planning on having a CsWinRT release along with a Windows SDK projection release by early next week after which you would be able to use the Otherwise you would need to try to generate the Windows SDK projection using the CsWinRT version built using what is in master. One thing I discovered when investigating this issue is that part of the problem was that WebView was calling CreateStreamOverRandomAccessStream on the UI thread to convert the IRandomStream passed as a content to an IStream. This was what was the core of the deadlock and not the thread which the IRandomStream is created on. |
@manodasanW that should definitely be sufficient, as I'm only using CsWinRt via the WindowsAppSdk nuget package for the projects in question. (I remember the earlier WinUI 3 releases had us add a separate nuget reference to CsWinRt, but I can see now that CsWinRt seems to be baked into the WindowsAppSdk binary as its not even a transitive dependency.) Thanks for explaining your discovery about the reasons for the deadlock. I'm guessing the reason WebView2 didn't block the UI thread if given a native WinRT stream rather than a Win32/.NET stream turned into an IRandomAccessStream (created from the same thread context/under the same scheduler) has to do with the fact that a concrete WinRT FileInputStream/XxxStream is marshalled as an agile object directly while the Win32 stream (for some reason) isn't? (Although both end up converted to the non-agile IRandomAccessStream, I imagine some marshaling operation is optimized to a no-op dependent on the underlying concrete object?) My reference to the apartment model was because of the old version of the docs which stated
That sent me on a wild goose chase of trying to create the Win32/.NET stream on a background STA thread (though I could not see how that could actually be the case given the observed behavior). |
@mqudsi The Windows SDK projection is actually shipped as a targeting pack which is implicitly pulled in by the .NET SDK when you use the net<5/6/7>.0-windows10.0.xxx.0 TFMs. WindowsAppSDK takes an implicit dependency on it via the TFM. Yesterday, we shipped an updated version of the Windows SDK projection and that will be pulled in by the next .NET SDK update when it comes out. But in the meantime, if you want to try out the fix, you can make .NET SDK use a version of the Windows SDK projection you specify by setting the following property in your application project:
You should remove this once the next .NET SDK update comes out and you move to it given it overrides the Windows SDK projection version even if the .NET SDK has a newer version available. With regards to the other point, I believe internally in the OS there are optimizations for the WinRT InMemoryRandomAccessStream which meant that the non agile IStream was taking advantage of the agile behavior of it whereas for other passed IRandomMemoryStreams such as the one we implement, it doesn't. |
I hate that Visual Studio lets me (or even prompts me) to upgrade to a newer version of a dependency that doesn't support the runtime - using WinAppSDK 1.0.0 or 1.0.1 completely breaks The good news: as you suggested, just pinning |
Per the discussion in #1126, the async operation itself shouldn't synchronize the context which is used to fire handlers. Instead, it is the responsibility of the awaiter to capture the context and synchronize if the caller of the async operation would like to. For instance, the awaiter in C# tasks by default captures context and fires the handler on the same context by making use of SynchronizationContext, but the caller is also able to configure that behavior using ConfigureAwait. Similar functionality also exists in C++/WinRT via co_await. Due to that, I am initially making a change to stop using the context to fire handlers which should also resolve the deadlock in the below mentioned issue. In a future release, we can then clean up the code assuming we hear about no issues from this change. Testing of some apps with this change have so far shown no issues.
Fixes #670