Skip to content
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

ASYNC Main Does not Respect [STAThread] #22112

Closed
TonyValenti opened this issue Sep 14, 2017 · 18 comments
Closed

ASYNC Main Does not Respect [STAThread] #22112

TonyValenti opened this issue Sep 14, 2017 · 18 comments
Assignees
Milestone

Comments

@TonyValenti
Copy link

Version Used:
2017.3
Steps to Reproduce:
Run this code:

[STAThread]
static async Task Main(string[] args) {
	Console.WriteLine(System.Threading.Thread.CurrentThread.ApartmentState);
}

Expected Behavior:
I expect the thread to be STA.

Actual Behavior:
The thread is MTA.

@TonyValenti
Copy link
Author

TonyValenti commented Sep 14, 2017

When I look at the code in JustDecompile, this is what I see (You'll notice that the [STAThread] does not get copied to the "real" main:

        private static void <Main>(string[] args)
        {
            Program.Main(args).GetAwaiter().GetResult();
        }

        [STAThread]
        private static async Task Main(string[] args)
        {
            Program.<Main>d__0 variable = null;
            AsyncTaskMethodBuilder asyncTaskMethodBuilder = AsyncTaskMethodBuilder.Create();
            asyncTaskMethodBuilder.Start<Program.<Main>d__0>(ref variable);
            return asyncTaskMethodBuilder.Task;
        }

@tannergooding
Copy link
Member

FYI. In addition to this, there is also a more general issue for it not being respected in .NET Core: https://github.com/dotnet/coreclr/issues/13688

There was also some discussion of this issue (async main) here: dotnet/csharplang#97

@jcouv
Copy link
Member

jcouv commented Sep 14, 2017

FYI @TyOverby

@gafter gafter added the Bug label Sep 15, 2017
@gafter gafter added this to the 15.5 milestone Sep 15, 2017
@jaredpar jaredpar modified the milestones: 15.5, 15.later Oct 12, 2017
@jaredpar jaredpar assigned agocke and unassigned TyOverby Jan 5, 2018
@jaredpar jaredpar modified the milestones: 15.6, 15.7 Jan 5, 2018
@agocke
Copy link
Member

agocke commented Jan 10, 2018

As mentioned in dotnet/csharplang#97, this was explicitly considered and rejected by LDM. In addition, it sounds as though putting the attribute on the generated main method is not sufficient, anyway.

Regardless, this needs to be taken through the dotnet/csharplang repo and LDM before we'd consider a compiler change here.

@houseofcat
Copy link

houseofcat commented Mar 23, 2022

@agocke

This broke .NET Framework older versions like 4.6.2 and a WinForms project. Just wasted hours triaging why I can't put text into a Clipboard.

I am unable to adjust language versions, but this supports C# 7.3 (or should).

This needs to be reopened. This is a defacto bug (as of Visual Studio 2019 (v17.1))

image

@CyrusNajmabadi
Copy link
Member

@houseofcat The post above yours (#22112 (comment)) discusses how any change would have to happen here.

@houseofcat
Copy link

houseofcat commented Mar 23, 2022

That work has come and gone. Nobody is patching .NET Framework (unless its a security KB hotfix) or releasing C# 7.4.

The only non-atrocious work around is simply not to use async Main in WinForms projects.

@CyrusNajmabadi
Copy link
Member

Could you explain what broke then? Was there a particular change recently that caused existing working code to suddenly stop working? Or is this just a case of async-main working in a particular way (As it always has) and you dislike the choices on how that works? Thanks!

@houseofcat
Copy link

houseofcat commented Mar 23, 2022

Correct, I modernized an API to using async / await. Simple introduction into the WinForms application, specifically adding an await inside of Main and in lieu of .GetAwaiter().GetResult().

Work around is simple, don't use async await. Discovering the apartment state of a UI is MTA when it was and supposed to be STA was difficult to figure out the cause... hence me resurrecting old threads that should not have been closed. The idea being others don't have to experience this.

@CyrusNajmabadi
Copy link
Member

hence me resurrecting old threads that should not have been closed

This issue is closed as the compiler is working as per the expected design. If you want the design to change, it would need to go through the process outlined in the link above.

@houseofcat
Copy link

houseofcat commented Mar 23, 2022

I wish I could close software tickets on buggy software because its working as I expected it to.

Let me ask:
Is the STAThread thread apartment attribute above Main working when Main is an async Task or async void ?

If not then your expected design isn't working. Now, the compiler could issue a WARN or ERROR to tell the developers that it isn't included in the expected design and I really couldn't say anything, because then IT WOULD be working according to your expected design as you actually alerted developers it doesn't work.

@CyrusNajmabadi
Copy link
Member

CyrusNajmabadi commented Mar 23, 2022

I wish I could close software tickets on buggy software because its working as I expected it to.

You can. For any project you are a maintainer of.

You get to determine what is acceptable/expected behavior and you can handle your bugs accordingly. Otherwise, it would not be possible for maintainers to close bugs as any user could say "i still think this is buggy, so you have to keep it open".

@CyrusNajmabadi
Copy link
Member

Now, the compiler could issue a WARN or ERROR to tell the developers that it isn't included in the expected design and I really couldn't say anything, because then IT WOULD be working according to your expected design as you actually alerted developers it doesn't work.

We don't generally alert people for all the things they think work some way when it doesn't actually work that way. Such a set of alerts/warnings/errors is effectively unbounded as every customer may have their own set of expectations that aren't met. To that end, we have an extensible compiler architecture where anyone can augment teh analysis we do with their own set of expectations, getting alerts/warnings/errors when things don't work out that way.

This allows the ecosystem to invest in the areas it feels are worthwhile, even if they don't align with the areas the project maintainers views as falling under their purview.

@CyrusNajmabadi
Copy link
Member

@houseofcat Again, we have a process for changes to happen. If you believe this behavior in the compiler should change, please follow that process.

@jmarolf
Copy link
Contributor

jmarolf commented Mar 24, 2022

Agree with @CyrusNajmabadi that we may want a specific analyzer in the SDK about using async main in Winforms. @RussKie does that sound like something that is reasonable to you?

@RussKie
Copy link
Member

RussKie commented Mar 24, 2022

Thank for roping me in.

Looking at this code I can agree that the behvaiour can totally look unexpected.

[STAThread]
public static async Task Main()
{
    // state == MTA
}

At the same time my main question about this code - what does it mean to start an async Windows Forms app? So while the behaviour is surprising, I don't believe this would be a supported scenario. Just because the language support this construct, it doesn't mean the SDK supports, and you should use it.

As far as the idea of an analyzer that would issue a warning when a developer tries to use STAThread with async Main - I think it may be a good idea.

@houseofcat
Copy link

I appreciate the consideration. My sole concern was to help people who come across this.

@RussKie

@janseris
Copy link

janseris commented Jan 10, 2023

Thank for roping me in.

Looking at this code I can agree that the behvaiour can totally look unexpected.

[STAThread]
public static async Task Main()
{
    // state == MTA
}

At the same time my main question about this code - what does it mean to start an async Windows Forms app? So while the behaviour is surprising, I don't believe this would be a supported scenario. Just because the language support this construct, it doesn't mean the SDK supports, and you should use it.

As far as the idea of an analyzer that would issue a warning when a developer tries to use STAThread with async Main - I think it may be a good idea.

I just came across this at first weird error until I found out that it's MTA in that main to my surprise just as you show.
The use case was: Dependency Injection setup with an async/await DB call to set up empty database for dev version of a WinForms app then start the app itself (Application.Run(Form1)...
This resulted in crash on Ctrl+V because ClipBoard in WinForms probably expects Single-Threaded Apartment.

A warning or more would be nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests