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

Avoid using LoadAsync() method of PictureBox control #242

Closed
KlausLoeffelmann opened this issue Dec 13, 2018 · 13 comments
Closed

Avoid using LoadAsync() method of PictureBox control #242

KlausLoeffelmann opened this issue Dec 13, 2018 · 13 comments
Labels
🪲 bug Product bug (most likely) tenet-compatibility Incompatibility with previous versions or with WinForms for .NET Framework

Comments

@KlausLoeffelmann
Copy link
Member

KlausLoeffelmann commented Dec 13, 2018

Steps to reproduce:

  1. Create a new WinForms Core App.
  2. Add the following Code to the Form's constructor.
public Form1()
        {
            InitializeComponent();
            System.Windows.Forms.PictureBox pb = new PictureBox();
            pb.ImageLocation = @"\\winformssrvvm01\BAQAFiles\v-mikou\OGF Doc\picture\myLargeImage1.bmp";
            pb.LoadAsync();
        }
  1. Run the app.

Expected Result: LoadAsync should be executed. (NOTE: Although LoadAsync implies this, the method does not return Task but void, so the usage here is correct with regards to async/await.)

Actual Result: An exception pops up, please see following screenshot and exception log.

image

Exception log:

System.PlatformNotSupportedException
  HResult=0x80131539
  Message=Operation is not supported on this platform.
  Source=System.Private.CoreLib
  StackTrace:
   at System.Threading.WaitCallback.BeginInvoke(Object state, AsyncCallback callback, Object object)
   at System.Windows.Forms.PictureBox.LoadAsync()
   at XpictureIssue.Form1..ctor() in C:\Users\v-zheshi\source\winforms\XpictureIssue\Form1.cs:line 20
   at XpictureIssue.Program.Main() in C:\Users\v-zheshi\source\winforms\XpictureIssue\Program.cs:line 19
@jnm2
Copy link
Contributor

jnm2 commented Dec 13, 2018

The BeginInvoke call is something I think https://docs.microsoft.com/dotnet/standard/analyzers/api-analyzer would have caught at compile time, IIRC.

@merriemcgaw merriemcgaw added 🪲 bug Product bug (most likely) tenet-compatibility Incompatibility with previous versions or with WinForms for .NET Framework labels Dec 13, 2018
@merriemcgaw merriemcgaw added this to the 3.0 milestone Dec 13, 2018
@KlausLoeffelmann
Copy link
Member Author

@ericstj , could you take a look?

@KlausLoeffelmann
Copy link
Member Author

KlausLoeffelmann commented Dec 14, 2018

In addition: What do folks think about making this method Obsolete, and come up with a new one which does keep what its promising (namely returning Task and not void)?

@weltkante
Copy link
Contributor

weltkante commented Dec 14, 2018

It doesn't promise returning a Task, that's some naming convention which was invented way later than WinForms. Errors are reported through LoadCompleted event, would you obsolete that as well or expose the same error twice through different means?

Without having a proper infrastructure for async support in the WinForms framework I see little value in adding Task support for this particular method. How would existing callers be migrated to await the Task? Existing callers are most likely not in an async method so awaiting for purpose of observing potential errors is trouble most callers probably discard (and then get killed by unhandled exceptions if an error actually happens and they didn't observe it, I see that kind of lazy programming crashes constantly in UWP apps where async is forced onto the UI and people ignore error handling because the framework provides no easy way to do it correctly).

Alltogether, I agree WinForms needs to think about async support, but this is probably not a good place to start with.

@KlausLoeffelmann
Copy link
Member Author

KlausLoeffelmann commented Dec 14, 2018

Alltogether, I agree WinForms needs to think about async support, but this is probably not a good place to start with.

I think we just have! 😊

Think about the target audience for a second that WinForms has - this is quite different from what you normally have in Core. So, I think, this might be even a great opportunity to start, because the use case is simple and straight forward. On top I expect the actual usage of this method extremely low. And at the same time, I expect that the typical Windows audience expects the usage of this method extremely differently: If a Dev sees this method ending with Async, they will be rather surprised not getting back a Task or some Async operation/result.

So, obviously it's not my intension to break existing apps. What's in is in and no one wants to take that out. But I don't see any reason to tag both methods with Obsolete and advertise an new way with "Hey, there's a better way to do this - here is how it's done:" and refer to an alternative implementation?

@asmaaswt
Copy link

asmaaswt commented Dec 15, 2018

البرمجة بالعربية غير مدعومة

Automated translation: Programming in Arabic is not supported

@karelz
Copy link
Member

karelz commented Dec 15, 2018

@asmaaswt we use English in our repos - we not have capability and/or capacity to use other languages. English is treated as most common language for most developers world-wide.

I used automated translation (updated above), but I am not sure if it is correct, or how it relates to this specific issue. Can you please explain in more details what you meant and how it relates to this issue? Thanks!

@kevingosse
Copy link
Contributor

kevingosse commented Dec 16, 2018

The BeginInvoke call is something I think https://docs.microsoft.com/dotnet/standard/analyzers/api-analyzer would have caught at compile time, IIRC.

I gave it a try, to my surprise Delegate.BeginInvoke is not detected by the analyzer.

@ericstj
Copy link
Member

ericstj commented Dec 17, 2018

Just to confirm, I believe this is intentional per
https://github.com/dotnet/corefx/issues/5940#issuecomment-182107557 /cc @jkotas. You'll need to make a fix to WinForms here to avoid this API. The comment here may not even apply any more on Core so perhaps you can just call BeginGetResponse

// Invoke BeginGetResponse on a threadpool thread, as it has
// unpredictable latency, since, on first call, it may load in the
// configuration system (this is NCL
(new WaitCallback(BeginGetResponseDelegate)).BeginInvoke(req, null, null);

Alternatively just use the Task infrastructure to run the code on a background thread.

In addition: What do folks think about making this method Obsolete, and come up with a new one which does keep what its promising (namely returning Task and not void)?

We had similar goals back in .NETCore1.0 but dialed it back. In most cases it's not worth breaking someone over just having a newer API. There should be some really good reason to force a dev to think about the change. "New" is not a good enough reason. Thus we still have all the old event-based and APM based API next to task based API.

It's a reasonable goal to plumb task-based async API through WinForms, but that should be done in a wave impacting all async winforms APIs. That way you aren't forcing people to learn two different async programming models. I can imagine that being a pretty huge task given that WinForms relies heavily on the event-based model.

@OliaG OliaG added the help wanted Good issue for external contributors label Dec 17, 2018
@merriemcgaw merriemcgaw changed the title PlatformNotSupported Exception thrown by LoadAsync() method of PictureBox control Avoid using LoadAsync() method of PictureBox control Mar 29, 2019
@merriemcgaw
Copy link
Member

Closing per @ericstj comment above. This is by design.

@jkotas
Copy link
Member

jkotas commented Apr 20, 2019

@merriemcgaw The runtime behavior is by design, but there should be a fix made in WinForms to compensate for it.

https://devblogs.microsoft.com/dotnet/migrating-delegate-begininvoke-calls-for-net-core/ has detailed guidance on what to change BeginInvoke to.

@jnm2
Copy link
Contributor

jnm2 commented Apr 20, 2019

@kevingosse

The BeginInvoke call is something I think https://docs.microsoft.com/dotnet/standard/analyzers/api-analyzer would have caught at compile time, IIRC.

I gave it a try, to my surprise Delegate.BeginInvoke is not detected by the analyzer.

This has been fixed and the release will be coming soon. dotnet/platform-compat#130 (comment)

RussKie added a commit to RussKie/winforms that referenced this issue Aug 30, 2019
Async delegates have been deprecated in .NET Core (see https://github.com/dotnet/corefx/issues/5940)
for reasons such as:
* Async delegates use deprecated IAsyncResult-based async pattern.
This pattern is generally not supported throughout .NET Core base libraries.
* Async delegates depend on remoting (System.Runtime.Remoting) under the
hood. Remoting is not supported in .NET Core.

For more detailed reasons and migration strategies please refer to
https://devblogs.microsoft.com/dotnet/migrating-delegate-begininvoke-calls-for-net-core/

In case of WinForms, async pattern predates the Task-based Asynchronous
Pattern and it does not return awaitables.
In order to minimise the change to the public API surface we continue
to expose the existing API and just re-route the image loading routine
to a `Task` runner under the covers.

Fixes dotnet#242
Fixes dotnet#1548
@ghost ghost removed the 🚧 work in progress Work that is current in progress label Sep 3, 2019
@RussKie RussKie modified the milestones: 3.0-Preview5, 3.0-GA Sep 3, 2019
@Zheng-Li01
Copy link
Member

Verified this bug with .Net core 3.0.100-rc1-014190 from release branch, the issue has been fixed.

@ghost ghost locked as resolved and limited conversation to collaborators Feb 8, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
🪲 bug Product bug (most likely) tenet-compatibility Incompatibility with previous versions or with WinForms for .NET Framework
Projects
None yet
Development

No branches or pull requests