Task.FromResult().Result wird nicht returned (Serveranfrage)

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Task.FromResult().Result wird nicht returned (Serveranfrage)

    Moin zusammen :)

    ich bin gerade dabei, eine Funktion zu schreiben, die meinen User autorisiert, mit meiner App Daten von Discogs zu laden (mit dem NuGet-Paket DiscogsClient). Nur leider sieht es so aus, als ob der Server nicht antwortet. Wenn ich die Funktion ausführe, ist in Zeile 3 Schluss, und es passiert rein gar nichts, auch keine Fehlermeldung:

    VB.NET-Quellcode

    1. ​Dim OAuthConsumerInformation = New OAuthConsumerInformation("MeinConsumerKey", "MeinConsumerSecret")
    2. Dim discogsClient = New DiscogsAuthentifierClient(OAuthConsumerInformation)
    3. Dim aouth = discogsClient.Authorize(Function(s) Task.FromResult(GetToken(s))).Result
    4. Dim successString As String = ""
    5. If aouth IsNot Nothing Then successString = "erfolgreich." Else successString = "nicht erfolgreich."



    VB.NET-Quellcode

    1. Private Function GetToken(ByVal url As String) As String
    2. Process.Start(url)
    3. Dim InputVM = New ViewModel.InputBoxDialogViewModel("Bitte registriere dich bei Discogs. Dein Standardbrowser hat sich jetzt automatisch geöffnet. Nach der Registrierung, wenn du nicht bereits registriert bist, wird ein Code angezeigt. Bitte gebe diesen hier ein:")
    4. dialogService.ShowModalDialog("", InputVM, Me, True, False, Services.WindowStyle.None, Services.ResizeMode.NoResize, 500, Services.SizeToContent.Height, Services.WindowStartupLocation.CenterScreen, "")
    5. 'Console.WriteLine("Please authourize the application and enter the final key in the console")
    6. 'Dim tokenKey As String = Console.ReadLine()
    7. Dim tokenkey As String = InputVM.InputText
    8. tokenkey = If(String.IsNullOrEmpty(tokenkey), Nothing, tokenkey)
    9. Return tokenkey
    10. End Function


    Das hier ist das Demoprogramm, das funktioniert tadellos:

    C#-Quellcode

    1. namespace DiscogsAuthenticationConsole
    2. {
    3. public class Program
    4. {
    5. public static void Main(string[] args)
    6. {
    7. var oAuthConsumerInformation = new OAuthConsumerInformation("MeinConsumerKey", "MeinConsumerSecret");
    8. var discogsClient = new DiscogsAuthentifierClient(oAuthConsumerInformation);
    9. var aouth = discogsClient.Authorize(s => Task.FromResult(GetToken(s))).Result;
    10. Console.WriteLine($"{((aouth != null) ? "Success" : "Fail")}");
    11. Console.WriteLine($"Token:{aouth?.TokenInformation?.Token}, TokenSecret:{aouth?.TokenInformation?.TokenSecret}");
    12. Console.ReadLine();
    13. }
    14. private static string GetToken(string url)
    15. {
    16. Console.WriteLine("Please authourize the application and enter the final key in the console");
    17. Process.Start(url);
    18. string tokenKey = Console.ReadLine();
    19. tokenKey = string.IsNullOrEmpty(tokenKey) ? null : tokenKey;
    20. return tokenKey;
    21. }
    22. }
    23. }


    Ich hab mir das ganze automatisch nach VB übersetzen lassen.

    Die einzige Änderung, die ich vorgenommen habe, war, dass ich Private Function GetToken nicht als Shared deklariert habe, denn da kam bei mir der Fehler in der Zeile, wo ich die InputBox aufrufe mit dialog.ShowModalDialog():

    BC30369: Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class
    Auf einen Instanzmember einer Klasse kann nicht ohne explizite Instanz einer Klasse von einer/einem freigegebenen Member / Methode aus verwiesen werden.

    Hab mir mal durchgelesen, was dieses Shared genau macht, aber so wie ich dass sehe, sollte das eigentlich nix damit zu tun haben oder?

    Den ersten Code in Zeile 3 versteh ich auch nicht so ganz, ist da vielleicht ein Fehler beim Übersetzen nach VB drin. Mein Virenscanner meldet jedenfalls dass eine Verbindung aufgebaut wird, aber wie gesagt, wenn ich dann auf "Zulassen" klicke, passiert gar nichts...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Okay dank einem Hinweis von @Nofear23m weiss ich nun, dass ich statt Task.FromResult das Ganze mit Async/Await lösen sollte, da es kein Konsolenprogramm ist, sondern UI-basiert.

    Also hab ich mir gedacht ich schreib das so um...:

    Dim aouth = discogsClient.Authorize(Async Function(s) Await GetToken(s)).Result

    ...und die Methode, in der diese Zeile ist, definiere ich als Async

    Da meldet der Compiler dann

    BC36930 "Await" erfordert, dass der Typ String eine geeignete GetAwaiter-Methode aufweist.

    Wenn ich dann auf das BC36930 kllicke, kommt nur der freundliche Hinweis, "Hoppla! Es wurde keine F1-Hilfe gefunden." und auch wenn ich in den MS Docs nach GetAwaiter-Methode schaue, kommt da genau eine einzeilige Definition, mehr nicht.

    Kann mir jemand helfen?

    Edit:
    Okay hab jetzt das hier:

    VB.NET-Quellcode

    1. Dim aouth = discogsClient.Authorize(Function(s) GetToken(s)).GetAwaiter.GetResult


    und das:

    VB.NET-Quellcode

    1. Private Async Function GetToken(ByVal url As String) As Task(Of String)


    Aber immer noch das Gleiche: Es passiert nichts...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    ich würd erstmal versuchen, mit einer vb.net-Konsolen-Anwendung überhaupt mal was funktionierendes hinzukriegen. Async anonyme Methoden, oder .GetAwaiter habich nochnie gesehen.
    ansonsten probierma bischen rum: Dim aouth = discogsClient.Authorize(Async Function(s) Await GetToken(s).GetAwaiter).Result
    und mal mit async, mal ohne.

    Aber v.a. probier mit einer Shared Methode, weil das scheint ja die einzige Abweichung vonne Vorlage zu sein.
    Nur um zu gucken, ob die erreicht wird.


    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ja mein VB.NET Code funktioniert nicht, der C# Code funktioniert....

    Ich bin echt auch ratlos, bin schon seit Stunden am Googeln....

    Ich versteh halt auch nicht, wie das Argument s den Wert für die URL bekommt. Die muss ja dann irgendwie von .Authorize kommen...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Also wenn man das direkt nach VB übersetzt und als Konsole startet, funktioniert es auch, auch ohne Shared.


    Und wenn ich das mache:

    VB.NET-Quellcode

    1. Dim aouth = discogsClient.Authorize(Async Function(s) Await GetToken(s).GetAwaiter).Result


    ... kommt "GetAwaiter" ist kein Member von "String".

    und ohne Async:

    "Await" kann nur in einem Async-Lambdaausdruck verwendet werden.

    Ich probiers mal hiermit:

    VB.NET-Quellcode

    1. Dim aouth = Await discogsClient.Authorize(Function(s) GetToken(s))


    und:

    VB.NET-Quellcode

    1. Private Async Function GetToken(ByVal url As String) As Task(Of String)
    2. Await Process.Start(url)


    ...Dann kommt: Await erfordert, dass der Typ Process eine geeignete GetAwaiter-Methode aufweist...

    Hmmm...
    Also wenn ich das mache:

    VB.NET-Quellcode

    1. Dim aouth = discogsClient.Authorize(Async Function(s) Await GetToken(s)).GetAwaiter.GetResult


    oder auch:

    VB.NET-Quellcode

    1. Dim aouth = discogsClient.Authorize(Function(s) GetToken(s)).GetAwaiter.GetResult


    und das:

    VB.NET-Quellcode

    1. Private Async Function GetToken(ByVal url As String) As Task(Of String)
    2. Process.Start(url)


    Geht er nicht mal in die Methode GetToken rein...

    Jetzt hab ich bei meiner Recherche gelesen, dass Async Functions nichts zurückgeben, wenn kein Awaitirgendwo drin ist, was ja bei mir der Fall ist...

    Das würde ich ja entweder vor Process.Start setzen oder vor dialogServcice.ShowModalDialog. Aber da kommt dann wieder:

    Await erfordert, dass der Typ Process (bzw. Boolean bei dialogService) eine geeignete GetAwaiter-Methode aufweist...

    Wenn ich das (.GetAwaiter.GetResult) aber anhänge, kommt:

    GetAwaiter ist kein Member von Process / Boolean.

    kafffee schrieb:

    Geht er nicht mal in die Methode GetToken rein...
    wo geht er dann stattdessen hin?
    Vor allem interessiert mich der Code aus post#1, also ohne das Await-Brimborium.
    Weil das versteh ich nicht, wie das funzen soll, und die funktionierende Vorlage arbeitet ja auch ohne das.

    Also wohin geht er nach (post#1)

    VB.NET-Quellcode

    1. Dim aouth = discogsClient.Authorize(Function(s) Task.FromResult(GetToken(s))).Result
    ?
    und - nächster Versuch: Kannst du GetToken() mal radikal vereinfachen:

    VB.NET-Quellcode

    1. Private Function GetToken(ByVal url As String) As String
    2. return "walhalla"
    ?
    geht er dann da immer noch nicht rein?

    ErfinderDesRades schrieb:

    wo geht er dann stattdessen hin?

    Ins Nirvana, als wäre nichts geschehen. Er geht weder zu GetToken noch in die nächste Zeile....

    ErfinderDesRades schrieb:

    Weil das versteh ich nicht, wie das funzen soll, und die funktionierende Vorlage arbeitet ja auch ohne das.

    Da sind wir schon zwei...


    ErfinderDesRades schrieb:

    Kannst du GetToken() mal radikal vereinfachen:

    Auch wenn ich das mache kein Unterschied, da geht das Programm weder in nächste Zeile noch wird "Walhalla" returned...
    Okay da muss ich bissle was umstellen, das lässt sich momentan nicht erahnen, ob das Programm einfriert, weil das ausgeführt wird, bevor das MainWindow geladen ist. Zu Ende issses jedendfalls nicht...

    Wat für ne Anweisung soll ich unter Finally reinschreiben?

    Edit: Also, habs grad getestet, das Programm friert ein. Im TryCatch Block wird Catch nicht ausgelöst.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    So, Nofear23m hatte zum Glück die Lösung parat:

    Einmal diese Klasse im ViewModel erstellen:

    VB.NET-Quellcode

    1. Imports System.Threading
    2. Imports System.Windows.Input
    3. Public Class AsyncRelayCommand : Implements ICommand
    4. Private ReadOnly _execute As Func(Of Object, Task)
    5. Private ReadOnly _canExecute As Func(Of Object, Boolean)
    6. Private isExecuting As Long
    7. Public Sub New(ByVal execute As Func(Of Object, Task), ByVal Optional canExecute As Func(Of Object, Boolean) = Nothing)
    8. Me._execute = execute
    9. Me._canExecute = If(canExecute, (Function(o) True))
    10. End Sub
    11. Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
    12. AddHandler(value As EventHandler)
    13. If _canExecute IsNot Nothing Then
    14. AddHandler CommandManager.RequerySuggested, value
    15. End If
    16. End AddHandler
    17. RemoveHandler(value As EventHandler)
    18. If _canExecute IsNot Nothing Then
    19. RemoveHandler CommandManager.RequerySuggested, value
    20. End If
    21. End RemoveHandler
    22. RaiseEvent(sender As Object, e As EventArgs)
    23. End RaiseEvent
    24. End Event
    25. Public Sub RaiseCanExecuteChanged()
    26. CommandManager.InvalidateRequerySuggested()
    27. End Sub
    28. Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute
    29. If Interlocked.Read(isExecuting) <> 0 Then Return False
    30. Return _canExecute(parameter)
    31. End Function
    32. Public Async Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
    33. Interlocked.Exchange(isExecuting, 1)
    34. RaiseCanExecuteChanged()
    35. Try
    36. Await _execute(parameter)
    37. Finally
    38. Interlocked.Exchange(isExecuting, 0)
    39. RaiseCanExecuteChanged()
    40. End Try
    41. End Sub
    42. End Class


    Und den restlichen Code wie folgt modifizieren:

    VB.NET-Quellcode

    1. Public Class MainViewModel
    2. Inherits ViewModel.Instrastructure.ViewModelBase
    3. Private dialogService As Services.IDialogWindowService = ServiceContainer.GetService(Of IDialogWindowService)
    4. Private _StartAuthorizing As ICommand
    5. Public ReadOnly Property StartAuthorizing() As ICommand
    6. Get
    7. If _StartAuthorizing Is Nothing Then _StartAuthorizing = New AsyncRelayCommand(AddressOf StartAuthorizing_Execute, Function(o) True)
    8. Return _StartAuthorizing
    9. End Get
    10. End Property
    11. Public Async Function StartAuthorizing_Execute(obj As Object) As Task
    12. Dim OAuthConsumerInformation = New OAuthConsumerInformation("MeinConsumerKey", "MeinConsumerSecret")
    13. Dim discogsClient = New DiscogsAuthentifierClient(OAuthConsumerInformation)
    14. Dim aouth = Await discogsClient.Authorize(Function(s) Task.FromResult(GetToken(s)))
    15. Dim successString As String = ""
    16. If aouth IsNot Nothing Then Debug.WriteLine("Authorisierung erfolgreich") Else Debug.WriteLine("Authorisierung nicht erfolgreich")
    17. End Function
    18. Private Function GetToken(ByVal url As String) As String
    19. Process.Start(url)
    20. Dim InputVM = New ViewModel.InputBoxDialogViewModel("Bitte registriere dich bei Discogs. Dein Standardbrowser hat sich jetzt automatisch geöffnet. Nach der Registrierung, wenn du nicht bereits registriert bist, wird ein Code angezeigt. Bitte gebe diesen hier ein:")
    21. dialogService.ShowModalDialog("", InputVM, Me, True, False, Services.WindowStyle.None, Services.ResizeMode.NoResize, 500, Services.SizeToContent.Height, Services.WindowStartupLocation.CenterScreen, "")
    22. If InputVM.Ergebnis = True Then
    23. Dim tokenkey As String = InputVM.InputText
    24. tokenkey = If(String.IsNullOrEmpty(tokenkey), Nothing, tokenkey)
    25. Return tokenkey
    26. Else
    27. Return ""
    28. End If
    29. End Function
    30. End Class