microsoft / WindowsAppSDK

The Windows App SDK empowers all Windows desktop apps with modern Windows UI, APIs, and platform features, including back-compat support, shipped via NuGet.
https://docs.microsoft.com/windows/apps/windows-app-sdk/
MIT License
3.77k stars 319 forks source link

Question: .NET 5 UWP apps are already possible, so when will official support arrive? #105

Closed Aminator closed 3 years ago

Aminator commented 4 years ago

Question: .NET 5 UWP apps are already possible, so when will official support arrive?

When it comes to .NET 5 support for UWP apps, we don't really have a clear answer yet to how that will look like and when it will come. UWP developers shouldn't have to be stuck on an old .NET version while Win32 developers are seemingly way ahead and can also use the new C#/WinRT language projection.

How to create a .NET 5 UWP app

What I found is that despite Microsoft telling us developers that creating UWP apps running on .NET 5 is not supported yet, it is actually quite easy to do today with minimal setup and it even works with WinUI 3. You can start off with the regular .NET 5 console app template and modify it from there. This process involves three steps: Modifying the project file, adding a package manifest file and generating a PRI file. Be sure to have the latest .NET 5 preview SDK and Visual Studio Preview installed. I have provided samples in this repository.

Project file

You need to add a few properties, NuGet packages and targets. I tried to make it as independent of Visual Studio and the Windows 10 SDK as possible.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <!--If this property is set to WinExe, the app will not spawn a console window.-->
    <OutputType>WinExe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
    <Nullable>enable</Nullable>
    <TargetPlatformVersion>10.0.19041.0</TargetPlatformVersion>
    <TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
    <!--Platforms are only necessary for WinUI 3 and only x86 and x64 are supported at this time.-->
    <Platforms>AnyCPU;x86;x64;ARM;ARM64</Platforms>
    <!--The Main method needs to be defined manually to avoid an exception.-->
    <DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>
  </PropertyGroup>

  <ItemGroup>
    <Content Include="AppxManifest.xml" CopyToOutputDirectory="PreserveNewest" />
    <Content Include="Assets\**" CopyToOutputDirectory="PreserveNewest" />
  </ItemGroup>

  <!--The C#/WinRT language projection and WinUI 3 is used in this project.-->
  <ItemGroup>
    <PackageReference Include="Microsoft.Windows.CsWinRT" Version="0.1.0-prerelease.200623.5" />
    <PackageReference Include="Microsoft.Windows.SDK.NET" Version="10.0.18362.3-preview" />
    <PackageReference Include="Microsoft.WinUI" Version="3.0.0-preview1.200515.3" />
  </ItemGroup>

  <!--Any XAML files that have a code-behind file need to be listed here.-->
  <ItemGroup>
    <Page Update="App.xaml">
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Page Update="MainPage.xaml">
      <Generator>MSBuild:Compile</Generator>
    </Page>
  </ItemGroup>

  <!--This target generates a resource file for your app based on the priconfig.xml file and the files in the output directory.-->
  <Target Name="MakePri" AfterTargets="Build">
    <Exec Command="&quot;$(MSBuildProgramFiles32)\Windows Kits\10\bin\$(TargetPlatformVersion)\x86\MakePri.exe&quot; new /pr $(OutputPath) /cf priconfig.xml /of $(OutputPath)resources.pri /o" />
  </Target>

  <!--The manifest needs to be registered with the OS and after doing this, your app will appear in the app list.-->
  <Target Name="RegisterManifest" AfterTargets="MakePri">
    <Exec Command="PowerShell Add-AppxPackage -Register $(OutputPath)AppxManifest.xml" />
  </Target>

</Project>

Package manifest

The package manifest named AppxManifest.xml is needed to register your app with the OS, but notice that it's not the regular Package.appxmanifest file you find in old UWP projects, which would generate the final AppxManifest.xml for you. If you use an existing one, be sure to remove the package dependency for UWP .NET Core and use the release version of VCLibs.

<Dependencies>
  <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.18362.0" MaxVersionTested="10.0.19041.0" />
  <PackageDependency Name="Microsoft.VCLibs.140.00" MinVersion="14.0.27810.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
</Dependencies>

For WinUI 3 you also need to add any types you use from it to your manifest. This also needs to be done for WinUI Desktop.

<Extension Category="windows.activatableClass.inProcessServer">
  <InProcessServer>
    <Path>Microsoft.UI.Xaml.Controls.dll</Path>
    <ActivatableClass ActivatableClassId="Microsoft.UI.Xaml.Controls.TreeView" ThreadingModel="both" />
    <ActivatableClass ActivatableClassId="Microsoft.UI.Xaml.Controls.TreeViewItem" ThreadingModel="both" />
  </InProcessServer>
</Extension>

Resources

It is necessary to have a file called resources.pri in your app for any assets, including XAML files, to be accessible by your app. This can be generated using MakePri.exe. It takes a configuration file called priconfig.xml as an input. You can create a new configuration file with the command makepri createconfig /cf priconfig.xml /dq en-US. Be sure to remove the following two tags if you want to only create a single resources.pri file.

<packaging>
  <autoResourcePackage qualifier="Language"/>
  <autoResourcePackage qualifier="Scale"/>
</packaging>

Entry point for WinUI 3

A custom entry point needs to be defined for WinUI 3 apps because the automatically generated one applies the STAThreadAttribute to the Main method, which causes a wrong thread exception.

public class Program
{
    private static void Main(string[] args)
    {
        ComWrappersSupport.InitializeComWrappers();

        Application.Start(p =>
        {
            DispatcherQueueSyncContext.SetForCurrentThread();
            new App();
        });
    }
}

Building and debugging

The project can be built either on the command line using dotnet build or in Visual Studio, though for WinUI 3 it currently needs to be done in Visual Studio. Do not start the app from Visual Studio, this would execute the .exe file directly and essentially be a Win32 launch. The app needs to be launched by clicking on the app list entry in the Start menu or the icon on the taskbar. A debugger can be attached from Visual Studio after the app has been started.

Issues

The biggest issues with this approach are:

Conclusions

I have been using .NET 5 and WinUI 3 in my own UWP projects for a few weeks now and it has been working quite well and I was able to take advantage of new .NET APIs that I didn't have access to before. The main issues come from WinUI 3 still being in preview, so there are still many missing pieces, which is why I wouldn't recommend it for production use just yet.

Through this process I also came to understand what the main difference between a UWP and a Win32 app is and it all has to do with how the app is launched. It is the EntryPoint on the Application element in the package manifest that determines if it will be a UWP or a Win32 launch. For UWP it will be YourProject.App and for Win32 it will always be Windows.FullTrustApplication.

It is also unclear if this type of app will be accepted in the Microsoft Store, so I would like to know more information about that. The other question remaining is the one I stated at the beginning: Since it is possible to build UWP apps running on .NET 5 today, what is the holdup on supporting it officially? It would be great if Microsoft provided additional tooling to make the process easier for developers. I would like to see a rough timetable on when we can see the issues I mentioned resolved. Hopefully we can see it officially supported whenever WinUI 3 is ready for production, so that UWP developers that make the switch can also take advantage of .NET 5 immediately.

pjmlp commented 3 years ago

The Win32 sandbox was already available on Windows 10X, check its session videos. Just now with the project frozen, who knows.

DjArt commented 3 years ago

The Win32 sandbox was already available on Windows 10X, check its session videos. Just now with the project frozen, who knows.

That's worst technology ever - it's just Hyper-V virtual machine with lightweight Windows 10 version. It's just workaround and not related to UWP sandbox model.

pjmlp commented 3 years ago

@DjArt Whatever it might be, that shows sandboxing isn't going away. However I no longer have high hopes for UWP.

Reunion is the confirmation that future is somehow Windows 7 development model plus some goodies from UWP back into Win32 stack, and adoption remains to be seen.

I for one am slowly fed up from all rewrites that took place since Windows 8 introduction.

ptorr-msft commented 3 years ago

Thanks for the healthy discussion, and for keeping it civil. Limitations with localhost networking have their own issue (#113); please add your feedback there or add a new item if this doesn't cover it.

To the question of sandboxing, there are two key concepts here that often get intermingled due to oversimplification and confusing messaging... I do not fault anyone for getting things mixed up :-).

From a design standpoint, the sandbox is about controlling access to resources; it is entirely distinct from which APIs you can access (WinRT, .NET, etc.) and some of their respective design choices (async, for example). In practice, it turns out that the WinRT APIs are often the only APIs that understand how to work within the sandbox, but that's a historical decision that Project Reunion is explicitly trying to undo. (The Microsoft Store's policy of banning "unsupported APIs" also comes into play, which is another complication we're trying to work through... but that has nothing to do with how apps behave at runtime; it's purely a policy decision around which apps can be listed in the Store).

Take file access for example (Issue #8).

The AppContainer sandbox simply controls which files an app has access to. An app with no capabilities can't access any user files; an app with the picturesLibrary capability can access only your photos; and an app with the broadFileSystemAccess capability can access all your files. I hope everyone agrees this is a good thing :-). Of course that's the Platonic Ideal, and reality isn't quite as rosy (What if I don't store my photos in the Pictures Library? Why does broadFileSystemAccess not have a popup prompt? etc.) but they are mostly implementation issues that can be fixed; they're not fundamental design flaws.

From an API perspective, things aren't nearly as good. None of the existing APIs, like CreateFile, System.IO, fopen or std::fstream work for user files. Not a single line of existing file-manipulation code works in an AppContainer. You must re-write the code to use Windows.Storage because that's the only API that was designed to work within the sandbox. And the Windows.Storage API made design decisions that cause it to be slow, heavily async, and have various other limitations that make it unpalletable to many app developers. We improved the situation somewhat with the ...FromApp APIs (Win32 APIs that are also designed to understand the sandbox) and then we layerd API Redirection on top of that (to allow some degree of code re-use) but it's still not enough for various reasons. Hence Issue #8 which is saying "we want to make any file access API work within the sandbox" so you can use your existing code and not have to re-write and re-architect to use async WinRT APIs.

But the sandbox doesn't require WinRT. The sandbox doesn't require async code. The sandbox just says "though shalt respect the user's privacy choices."

(And yes, the Windows 10X "Win32 Container" is a different technology than AppContainer).

As to the problems with .NET Native / CoreCLR... sorry you are having those problems. They are best raised over in the .NET repos.

ptorr-msft commented 3 years ago

@m98770

anything that tries to modify the system should be restricted from sandbox/pure UWP apps, but other than all that, developers should be given freedom to produce something useful beyond "some data fetching from the internet and displaying" clients.

Can you give some examples? Based on my previous comment above, if possible please try to separate out "sandbox issues" (where you want to access a resource but the AppContainer won't let you) from "API issues" (where you want to use an API or library but it's not supported).

ptorr-msft commented 3 years ago

@mcosmin222

Bugs that have been reported, such as the inability to use MediaPlaybackList with IBasicVideoEffect (due to MediaPlaybackItems getting randomly skipped) are never fixed

Can you please file an issue for this (if there isn't one already?)

The worst part is that the UWP app model makes you dependent on winRT to get things done. If you are missing/limited on a feature, well then though luck. At least with a fully featured .net API you could implement your own.

The UWP "app model" (that's another long topic... LOL) doesn't depend on WinRT; it's just that often the WinRT APIs are the only ones that work properly. It may seem like I'm splitting hairs or trying to defend the indefensible, but my goal is not to claim the system is perfect or that none of these issues exist. My goal is to help everyone understand the different overlapping parts of the technology so we can have productive conversations about which specific things are broken and thus need fixing. There's nothing fundamentally broken about the "app model" that wouldn't allow you to use any API you wanted to, it's "just work" (in some cases a lot of work haha) to make that happen. We want to let developers use the APIs they know and love (Win32, CRT, STL, .NET, etc.) which I think would address some of your feedback. Letting us know which specific APIs (or resources) are important to you helps us prioritize the work.

And last but not least, why all the async methods? Why not provide both async and sync methods? async does not make you inherently fast, quite the opposite.

There are two basic reasons. I am not defending them, just letting you know. And yes, I 100% agree that async code can make apps slower, introduces reentrancy bugs, makes debugging harder, and so on.

The first reason was the support for JavaScript and WWAs. JavaScript (and the web in general) has no concept of explicit threads (or at least, they didn't 10 years ago). Whilst a .NET or C++ developer could put long-running calls onto a background thread, JavaScript developers couldn't, and so async was a way to let web developers have responsive apps. This is a valid argument for having async methods, but doesn't explain why there aren't also sync methods.

The second reason, which does explain why there are no sync methods, was a desire to raise the quality of UX in Windows apps. We've all had cases where an app has ghosted over with "FooApp - (not responding)" in the title bar, and the idea was to eliminate those classes of bugs where an app made a long-running call on its UI thread, causing the entire app to hang and the user to have a bad experience. Thus the "sync calls can hang, all hangs are bad, hence all sync calls are illegal" point of view that lead to a heavily-async design pattern. This was a noble goal, made with the user in mind, but in hindsight didn't necessarily work out as well as intended.

BenJKuhn commented 3 years ago

@jtorjo, It's a minor point, but I might be able to shed some light on this: " I see the stack trace, but on async code I never get the whole stack. And I NEVER EVER get the line that caused the crash. Trust me, I've analyzed stack traces from AppCenter for over 6 months now."

I'm guessing a bit, but this may be what you're seeing Back when we were building Windows Runtime API infrastructure in Windows 8, we recognized that with everything being async, debugging was going to be challenging, so we built something called "async causality tracing" to support debuggers and provide a more useful view of the sequence of events leading up to a crash. It uses ETW tracing and stack capture to build up a history of stacks that led to the current async operation, and the debugger stitches them back together. Such a stack never actually existed, but it approximates the logical sequence of events. That features is typically only enabled by the debugger since it incurs non-trivial overhead to capture stacks & context information on each async operation, and maintain a useful history of async operations.

I know that doesn't help you solve your problem, but I hope it provides a bit more insight as to why you might see something different in a local debugger vs. a crash dump in AppCenter.

You might be able to add some in-app analytics or otherwise use the causality ETW events to leave some breadcrumbs that you can follow when looking at crash dumps. I'm not certain if you'll be able to turn on the trace from within the application though. You can see what the events look like by inspecting them in Windows Device Portal or xperf. Look for the trace provider Microsoft-Windows-AsynchronousCausality in the ETW logging tool. I hope that's helpful.

jtorjo commented 3 years ago

@BenJKuhn Thanks for the insight!

@mcosmin222 said earlier in this thread "And last but not least, why all the async methods? Why not provide both async and sync methods? ..."

Personally I'm really tired of having to come up with weird workarounds to the WinRT (async) system. In the future, I really really think you should provide sync counterparts for most methods. Otherwise, this async mambo jambo will end up biting everyone in the ass. I'm not against async per-se, I'm against not having an alternative.

Because when I get to run the app in Release, there will be issues, and, as you said, debugging those is pretty close to impossible. However, having a clear stack trace will make this child's play.

Let me give you an example of async madness (this is the latest, but I have countless): there's a function CanvasBitmap.LoadAsync - which you guessed, loads the bitmap from a stream asynchronously. But, if I'm inside the CanvasControl.Draw function, the LoadAsync blocks the thread, and .Draw never completes. This should NEVER EVER EVER happen.

Clearly, I found a workaround for it, but it took me ages- initially I thought CanvasBitmap.LoadAsync was broken. As I said, I have countless examples, where async is not only not helpful, but really the opposite.

I'm really curious whose' "great" idea was to break up everything in order to support Javascript (if I understood correctly @ptorr-msft explanations).

I'm not a dreamer (anymore), so I know we'll live with this current state of events for years to come. But hopefully our grand children or grand grand children will be able to have sync counterparts.

Pinox commented 3 years ago

@jtorjo So with you on this one. Recently used Xamarin,Essentials securestorage (async) on property getter and setters, Ugly stuff !! Best of all someone actually made the effort to include sync methods by adding a pull request on Github but was rejected eventually by James Montemagno. Problem with this mentality from MS is that it's not approachable for beginners and definitely not inclusive for the community that MS is trying to build. It's the same as a C# versus Visual Basic discussion. Stop the biasedness and embrace all the diversity in the community. Be "inclusive" and we will have a stronger community where everyone can express themselves.

https://github.com/xamarin/Essentials/pull/857

robloo commented 3 years ago

So with you on this one. Recently used Xamarin,Essentials securestorage (async) on property getter and setters, Ugly stuff !! Best of all someone actually made the effort to include sync methods by adding a pull request on Github but was rejected eventually by James Montemagno. Problem with this mentality from MS is that it's not approachable for beginners and definitely not inclusive for the community that MS is trying to build.

Couldn't agree more:

  1. Async can be a huge problem for new developers unless following very specific use cases that are well documented. It is not always intuitive especially for those coming from other languages how async/await works. New developers will mess up an app many ways regardless -- don't add complexity to try to think for developers, let them learn.
  2. Async is parasitic. Once one method starts using it the whole call stack usually needs to change to async/await if the result isn't void (this has been slightly improved over time). Of course there are ways around it but not always developer friendly or safe.
  3. For older/experienced developers it could either be:
    • Fine if you are writing a new code base
    • Terrible if you are using existing code that was already doing long running operations on different threads like it should be anyway.

Why Microsoft jumped whole heartedly into async/await while leaving sync in the dust I'll never understand. It certainly is not clear that it's better in all cases.

jtorjo commented 3 years ago

For older/experienced developers it could either be:

  • Fine if you are writing a new code base
  • Terrible if you are using existing code that was already doing long running operations on different threads like it should be anyway.

@robloo I know this wholeheartedly - basically, I ended up rewriting the whole UI - not for the faint hearted.

jtorjo commented 3 years ago

So with you on this one. Recently used Xamarin,Essentials securestorage (async) on property getter and setters, Ugly stuff !! Best of all someone actually made the effort to include sync methods by adding a pull request on Github but was rejected eventually by James Montemagno. Problem with this mentality from MS is that it's not approachable for beginners and definitely not inclusive for the community that MS is trying to build.

@Pinox I know - I've been crying against async for sooo long. But at some point I realized I need to move on and accept the fact that async is here to stay, and there's no way around it but to end up using it (I tried all sorts of stuff to add sync wrappers around, but they don't really work long term)

Pinox commented 3 years ago

@Pinox I know - I've been crying against async for sooo long. But at some point I realized I need to move on and accept the fact that async is here to stay, and there's no way around it but to end up using it (I tried all sorts of stuff to add sync wrappers around, but they don't really work long term)

I use 99% async where I can , but in some instances like property getter and setters I prefer a sync method. So in Xamarin,Essentials most Preferences are sync and not async but the securestorage is async but not sync. This goes over my head , why the double standards especially when most of the underlying functionality in the native platforms are actually sync methods.

I can still understand it when someone request a feature and then the maintainer has to write the code, but when someone actually writes the code and put in a pull request that then gets rejected. It's the "small things" that adds up and makes it unpleasant.

jonwis commented 3 years ago

For what it's worth, the new API design guidance for WinRT types since Windows.Foundation.UniversalApiContract version 8.0 has been to introduce non -Async methods based on demand, and that new APIs should come with both Foo.Bar() and Foo.BarAsync() methods. This guidance has been slowly being absorbed into API-making teams since then.

Per @BenJKuhn 's comment earlier, we recognized the challenges with this space for "normal" apps and that tooling - especially C++'s coroutines and C#'s SynchronizationContext (and this handy await pattern) means it's easy to move code off the UX thread and not block... but you have to know how to do it.

Our new design guidance is that you the developer own what goes on on your threads, and we should help you write "normal sequential code" whenever possible, with the option to easily hop off into async or into nonblocking contexts.

(We're working on getting these API design guidelines into the open so you can see why we make the APIs we do. Stay tuned!)

jtorjo commented 3 years ago

@jonwis

For what it's worth, the new API design guidance for WinRT types since Windows.Foundation.UniversalApiContract version 8.0 has been to introduce non -Async methods based on demand, and that new APIs should come with both Foo.Bar() and Foo.BarAsync() methods. This guidance has been slowly being absorbed into API-making teams since then.

That is beyond awesome!

Per @BenJKuhn 's comment earlier, we recognized the challenges with this space for "normal" apps and that tooling - especially C++'s coroutines and C#'s SynchronizationContext (and this handy await pattern) means it's easy to move code off the UX thread and not block... but you have to know how to do it.

I wasn't aware of that handy await pattern, it's definitely something worth knowing. Having said that, as I've written earlier, there are things a lot worse that just a bit of inconvenience, when it comes to async methods:

there's a function CanvasBitmap.LoadAsync - which you guessed, loads the bitmap from a stream asynchronously. But, if I'm inside the CanvasControl.Draw function, the LoadAsync blocks the thread, and .Draw never completes. This should NEVER EVER EVER happen

(just one of the countless examples I can come up with)

Long story short, I'd love for CanvasBitmap to have a sync Load() method. And same for BitmapEncoder/BitmapDecoder -they're kinda' in the same boat.

... (We're working on getting these API design guidelines into the open so you can see why we make the APIs we do. Stay tuned!)

Awesome, definitely looking forward to it!

brabebhin commented 3 years ago

@ptorr-msft

Can you please file an issue for this (if there isn't one already?)

223

Thanks.

driver1998 commented 3 years ago

Speaking of async, I wonder which is faster.

A:

public async Task DoLotsOfStuffAsync()
{
    await Task.Run(()=>{
        DoA();
        DoB();
        DoC();
        ...
    });
}

B:

public async Task DoLotsOfStuffAsync()
{
    await DoAAsync();
    await DoBAsync();
    await DoCAsync();
    ...
}
jtorjo commented 3 years ago

@driver1998 Very likely A.

On another note, I'm almost certain a lot of people don't realize that an "async Task" method executes synchronously until it needs to wait for something.

So in your case, A. executes completely on a different thread, while B. can have parts executing in the current thread, and parts executing on other threads.

ptorr-msft commented 3 years ago

FWIW, if A, B, and C are entirely independent (e.g. don't rely on shared state or contend for the same resources) then it might be fastest to do:

var tasks = new List<Task>();
tasks.Add(Task.Run(()=>DoA()));
tasks.Add(Task.Run(()=>DoB()));
tasks.Add(Task.Run(()=>DoC()));
await Task.WhenAll(tasks);

That's "github comment code", so take with a grain of salt :).

Eli-Black-Work commented 3 years ago

Yep 🙂 Or, if you already have async versions of the functions:

var tasks = new List<Task>();
tasks.Add(DoAAsync());
tasks.Add(DoBAsync());
tasks.Add(DoCAsync());

await Task.WhenAll(tasks);

Anyway, getting back on topic... 🙂

pfresnay commented 3 years ago

@Bosch-Eli-Black no ! 🙂 DoAAsync() can start with synchronous instructions before asynchronous one. Maybe you should do instead: tasks.Add(Task.Run(DoAAsync));

jtorjo commented 3 years ago

@Bosch-Eli-Black to quote myself:

On another note, I'm almost certain a lot of people don't realize that an "async Task" method executes synchronously until it needs to wait for something.

driver1998 commented 3 years ago

Anyway, just try to prove a point: If we have synchronous versions of WinRT IO APIs, then we can transfer these bulk operation (which is mostly written like B right now) to A. And maybe get some performance improvement.

Especially when we don't necessarily need to update the UI after every single operation, we just want a final result.

Arlodotexe commented 3 years ago

Getting back to the topic at hand, @pag3 @ptorr-msft do we have a definitive answer on what is holding us back from using .NET 5 with UWP?

In addition to the way you show, there are other approaches that can work, eg. starting with the packaged desktop app templates we’ve been shipping with the WinUI 3 previews and modifying them to have the apps execute/run as UWP apps instead of desktop apps.

We’d like to figure out the right path to enable this end-to-end, including not just the core platform and runtime working but also the tooling, project templates, deployment, store, etc. We’d like to support this in a way that’s forward-looking, durable, and makes it reasonably easy for developers to build apps with the benefits of UWP and the benefits of the latest .NET.

Is it the tooling and project setup path holding it back, is it more about AOT, (which could be delayed until .NET 6), a combination of both, or something else?

naikrovek commented 3 years ago

(I realize fully that this is not the time or the place for this comment, but it does relate to some things that have been said in this issue thread that I want to echo and elaborate on. I apologize for the interruption; please do not let my impulsiveness in posting this derail the thread further. I'm not trying to start this conversation up again, I only want to be heard, if only for a moment.)

Quoting a few of you, I want to point out a theme I have sensed, here:

an "async Task" method executes synchronously until it needs to wait for something.

[an async method inside a List<Task>] can start with synchronous instructions before asynchronous one.

this handy await pattern

etc.

How are people ever supposed to discover these things until they are bitten by them? Why does this particular language feature lay these landmines everywhere like it does? There are so many examples of C#'s async / await "gotchas" that, to me, it's not a language feature worth using anymore. I don't even write C# for myself anymore because of this API and how far this async stuff has spread within the framework libraries. All of my C# development difficulties for the past 3-4 years have always come down to some async/await sneak attack that I had not encountered before. Async & await were consistently the sole source of my C# headaches before I stopped writing code for fun in this language. It's no longer worth it for me to even use the .net framework AT ALL. Up until the pandemic, I had been writing C# for my own utilities and projects since about 2002.

This could have been such a beautiful language feature that made easy things easier, and hard things easier. Instead it made easy things harder and hard things the same, because people facing difficult problems fall back on what they know - threads. The lack of new synchronous APIs alongside the new async APIs was such an absolutely glaring oversight that persisted for so long that it felt like a middle finger from Microsoft. It really stung.

I feel this thread in my bones. I now do nearly all of my own software development in a non-.NET, language that makes async stuff absolutely trivial, and I'm so much happier for it. I mean imagine it: a single method that can be asynchronous or synchronous, depending on how it is called! There is no friction when moving between asynchronous and synchronous program design! I can switch any part at will, without a cascade of other changes that need to happen! I know! It doesn't offer the scheduling control that async and await in C# offer, and I have never once needed that control, and I don't know anyone that has needed that level of control that doesn't also just use plain threads... This API, this feature, whatever it is... it could have been good. It could have been really good. But instead it is worse than normal threads in every single way I care about.

Sorry for the interruption. I just wanted to be heard on that. To protect my sanity, and yours, I won't reply in this issue again.

VagueGit commented 3 years ago

Thank you @naikrovek for stating so passionately yet so clearly what so many of us feel. I know you do not wish to reply again in this thread, but please say where you went from DotNet so we can all see where the sky is blue.

ptorr-msft commented 3 years ago

do we have a definitive answer on what is holding us back from using .NET 5 with UWP?

@pag3 should have the latest info, but for one it is unlikely to pass Store certification. If you don't care about the Store, it can "work" but I do not believe it is officially supported.

ptorr-msft commented 3 years ago

@naikrovek thanks for sharing; indeed async programming has introduced new problems even as it attempted to solve old ones. I would suggest you provide your feedback to the C# team directly though.

brabebhin commented 3 years ago

@naikrovek

I feel your pain. For security critical code which doesn't really need to run in parallel but it is forced to do so by poor API interfaces only providing async, I have implemented a "Commands" dispatcher, which essentially runs these async methods sequentially and waits for each one of them to finish. This seems to have fixed many of the stringent bugs introduced by async.

I do not believe that async/await in C# is necessarily flawed. It is a very powerful tool. However, API interfaces that only allow async are problematic, mainly because they still introduce thread racing conflicts, even though it looks like they don't, which is why I hope project reunion will bring synchronous API equivalents for the myriad of async APIs in winRT.

jtorjo commented 3 years ago

There are so many examples of C#'s async / await "gotchas" that, to me, it's not a language feature worth using anymore

@mcosmin222 @naikrovek @ptorr-msft

async/await is a smart feature. The only problem is UWP. Or more to the point, WinRT. I've said it quite a few times - nobody at Microsoft is willing to work on fixing anything related to WinRT/UWP. They just postpone this until it'll die. Frankly, I do hope UWP dies, because it (WinRT) was a stupid idea to start with.

async/await do come with a few gotchas, but you can get the hang of them, and live another day. But what will kill you, is support for anything else - which came to the Desktop, but not to UWP. I have a feeling, it will NEVER arrive to UWP:

Not to add the countless Access Violation in PrivateCore.lib or something.

So yeah, can't wait for win2d to be ported to Desktop, so I can once and for all forget UWP ever existed.

DjArt commented 3 years ago

I do hope UWP dies, because it (WinRT) was a stupid idea to start with. Do you want to kill technology since you can't cook them right? Of course, for .NET projects there are some limitations, like NO STACK TRACE whatsoever or File:Line information in the stack trace (once again, this exists for Desktop, if you have .pdb files). since there used AOT compilation. ProjectN isn't so young for childish bugs, so if you want to debug your application, use the debug config and that's it.

jtorjo commented 3 years ago

since there used AOT compilation. ProjectN isn't so young for childish bugs, so if you want to debug your application, use the debug config and that's it.

Lol, have you ever actually developed an application that is used by ACTUAL USERS? Where something crashes and you simply have no way to reproduce? And you don't even know where to start?

Do you want to kill technology since you can't cook them right? Of course, for .NET projects there are some limitations, like NO STACK TRACE whatsoever

Yeah, please actually read before you comment. I did not say ".NET", I sad UWP. My whole point here was ".Net Desktop" works as it should, while UWP doesn't.

LATER EDIT: And in Debug, the crash clearly doesn't happen. Duh. DjArt, have you actually ever developed non-trivial UWP apps for the REAL WORLD, or do you just want to hear yourself talk?

Eli-Black-Work commented 3 years ago

@jtorjo, Let's keep it civil 🙂

MagicAndre1981 commented 3 years ago

@jtorjo Release uses .NET Native to compile managed to unmanaged code. You can also activate it for debug mode (which is done in ARM64 config for both debug and release) to see what causes your crashes.

jtorjo commented 3 years ago

@MagicAndre1981 Thanks for the suggestion. However, I'm not using .Net Native (I have it unchecked in Release as well)

pfresnay commented 3 years ago

@jtorjo if you publish your app to Microsoft Store as a regular UWP app (not a desktop bridge app), .NET Native is forced during "preprocessing" publish step.

jtorjo commented 3 years ago

@pfresnay I am very aware of that, I don't publish to MS Store. I am publishing it on my website. Fyi, you can check it out here - [link removed]

Arlodotexe commented 3 years ago

In the spirit of getting this discussion back on track (again), I reiterate my previous comment:

@pag3 @ptorr-msft, do we have a definitive answer on what is holding us back from using .NET 5 with UWP?

In addition to the way you show, there are other approaches that can work, eg. starting with the packaged desktop app templates we’ve been shipping with the WinUI 3 previews and modifying them to have the apps execute/run as UWP apps instead of desktop apps.

We’d like to figure out the right path to enable this end-to-end, including not just the core platform and runtime working but also the tooling, project templates, deployment, store, etc. We’d like to support this in a way that’s forward-looking, durable, and makes it reasonably easy for developers to build apps with the benefits of UWP and the benefits of the latest .NET.

Is it the tooling and project setup path holding it back, is it more about AOT, (which could be delayed until .NET 6), a combination of both, or something else?

yoshiask commented 3 years ago

do we have a definitive answer on what is holding us back from using .NET 5 with UWP?

If you don't care about the Store, it can "work" but I do not believe it is officially supported.

@ptorr-msft Is there a reason why it's not officially supported? If I'm not mistaken, WinUI 3 Desktop apps can be published to the Store without any issue. If WinUI 3 Desktop and WinUI 3 UWP apps are basically the same, does that mean it's the app model that's holding one back and not the other?

factormystic commented 3 years ago

Now that .NET 5 is out, I wondered if I could upgrade my UWP app to use it. I found this issue from google... still not sure what the answer is. Is the OP up to date and supported? (I'm not specifically asking about WinUI 3 which is what the discussion here at the bottom of the thread seems to be about)

The official .NET 5 announcement post only has 1 mention of UWP and says to check here. (yes I already checked the faq page... ctrl+f ".net" -> zero hits 😢)

ptorr-msft commented 3 years ago

@yoshiask UWP apps have different rules than Desktop apps. For example, the Store will try to run UWP binaries through .NET Native (which will fail) and it performs a Supported API Check to see what APIs you are using. Running the Windows App Certification Kit (WACK) locally on your PC should tell you what (if anything) is wrong, but it might not do the forced-.NET-Native step.

yoshiask commented 3 years ago

So I guess the real question is why doesn't the Store have a special case or a different set of rules for UWP apps that use .NET 5? Why is it hard-coded to force UWP apps to use .NET Native?

lukemcdo commented 3 years ago

This seems quite weird considering that C++ UWP apps are supported. Wouldn’t that mechanism also work for .NET 5 on UWP? Then just share the .NET 5 runtime via Framework Packaging.

ptorr-msft commented 3 years ago

@yoshiask :

why doesn't the Store have a special case or a different set of rules for UWP apps that use .NET 5

Because it's not supported.

@lmcdougald :

Then just share the .NET 5 runtime via Framework Packaging.

But no such package exists, because it's not supported.

Would it be nice if these things worked? Yes.

yoshiask commented 3 years ago

It seems like we're facing a bit of a chicken-and-egg problem here.

ptorr-msft commented 3 years ago

Not really. First the feature has to be supported, and then the other things can fall into place. There aren't any circular dependencies here.

sylveon commented 3 years ago

C++ apps are already native, so .NET Native has nothing to do @lmcdougald

lukemcdo commented 3 years ago

The point of the C++ comment is that it's clearly possible for code to run on UWP without .NET Native. .NET 5 should have nothing to do with .NET Native either.

ptorr-msft commented 3 years ago

@lmcdougald Windows doesn't care, but the Store assumes all managed binaries in a UWP project need to be .NET-native compiled. So they will see the DLLs and send them through the .NET Native compiler.

If you compiled the .NET 5 assemblies to native code (I can't recall whether there is such a tool or not yet) and built a "stand-alone" app (with no dependency on the shared framework) then you would probably fail the Supported APIs test. You can give it a shot though if you want to try (run WACK locally).

lukemcdo commented 3 years ago

Ok this is the type of detail I was hoping for. So it sounds to me like there's probably hacky ways to make this work (hide that they're DLLs and run them through something on first run) and it's a Store issue just about as much as it's a tooling issue?