Frage zu Events bei asynchronen Methoden

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 2 Antworten in diesem Thema. Der letzte Beitrag () ist von BornToBeRoot.

    Frage zu Events bei asynchronen Methoden

    Hallo Community,

    ich habe eine Frage zu Events by asynchronen Methoden.

    Bei Stackoverflow habe ich ein Beispiel gefunden (nachfolgender Code) und frage mich ob es auch anders funktioniert.

    Mein aktueller Code:

    Traceroute

    C#-Quellcode

    1. public class Traceroute
    2. {
    3. public void Trace(TracerouteInfo info, Action<TracerouteArgs> TouteReceived, Action TraceCompleted, Action UserHasCanceled, CancellationToken cancellationToken)
    4. {
    5. Task.Run(() =>
    6. {
    7. byte[] buffer = new byte[info.Buffer];
    8. Stopwatch stopwatch = new Stopwatch();
    9. using (Ping ping = new Ping())
    10. {
    11. try
    12. {
    13. for (int hop = 1; hop < info.MaximumHops; hop++)
    14. {
    15. // If user has clicked cancel
    16. cancellationToken.ThrowIfCancellationRequested();
    17. stopwatch.Start();
    18. PingReply pingReply = ping.Send(info.IPAddress, info.Timeout, buffer, new PingOptions() { Ttl = hop, DontFragment = info.DontFragement });
    19. stopwatch.Stop();
    20. string hostname = string.Empty;
    21. try
    22. {
    23. if (pingReply.Address != null)
    24. hostname = Dns.GetHostEntry(pingReply.Address).HostName;
    25. }
    26. catch (SocketException) { } // Couldn't resolve hostname
    27. TouteReceived(new TracerouteArgs(hop, stopwatch.ElapsedMilliseconds, pingReply.Address, hostname, pingReply.Status));
    28. if (pingReply.Address != null)
    29. {
    30. if (pingReply.Address.ToString() == info.IPAddress.ToString())
    31. {
    32. TraceCompleted();
    33. return;
    34. }
    35. stopwatch.Reset();
    36. }
    37. }
    38. }
    39. catch (OperationCanceledException)
    40. {
    41. UserHasCanceled();
    42. }
    43. }
    44. }, cancellationToken);
    45. }
    46. }



    TracerouteInfo

    C#-Quellcode

    1. public class TracerouteInfo
    2. {
    3. public IPAddress IPAddress;
    4. public int Timeout;
    5. public int Buffer;
    6. public int MaximumHops;
    7. public bool DontFragement;
    8. public TracerouteInfo()
    9. {
    10. }
    11. public TracerouteInfo(IPAddress ipAddress, int timeout, int buffer, int maximumHops, bool dontFragement)
    12. {
    13. IPAddress = ipAddress;
    14. Timeout = timeout;
    15. Buffer = buffer;
    16. MaximumHops = maximumHops;
    17. DontFragement = dontFragement;
    18. }
    19. }


    TracerouteArgs

    C#-Quellcode

    1. public class TracerouteArgs : EventArgs
    2. {
    3. public int Hop { get; set; }
    4. public double Time { get; set; }
    5. public IPAddress IPAddress { get; set; }
    6. public string Hostname { get; set; }
    7. public IPStatus Status { get; set; }
    8. public TracerouteArgs()
    9. {
    10. }
    11. public TracerouteArgs(int hop, double time, IPAddress ipAddress, string hostname, IPStatus status)
    12. {
    13. Hop = hop;
    14. Time = time;
    15. IPAddress = ipAddress;
    16. Hostname = hostname;
    17. Status = status;
    18. }
    19. }


    ViewModel

    C#-Quellcode

    1. public ICommand TraceCommand
    2. {
    3. get { return new RelayCommand(p => TraceAction()); }
    4. }
    5. private void TraceAction()
    6. {
    7. if (IsTraceRunning)
    8. StopTrace();
    9. else
    10. StartTrace();
    11. }
    12. CancellationTokenSource sourceToken;
    13. private async void StartTrace()
    14. {
    15. IsTraceRunning = true;
    16. TraceResult.Clear();
    17. // Try to parse the string into an IP-Address
    18. IPAddress ipAddress;
    19. IPAddress.TryParse(HostnameOrIPAddress, out ipAddress);
    20. try
    21. {
    22. // Try to resolve the hostname
    23. if (ipAddress == null)
    24. {
    25. IPHostEntry ipHostEntrys = await Dns.GetHostEntryAsync(HostnameOrIPAddress);
    26. foreach (IPAddress ip in ipHostEntrys.AddressList)
    27. {
    28. if (ip.AddressFamily == AddressFamily.InterNetwork && ResolveHostnamePreferIPv4)
    29. {
    30. ipAddress = ip;
    31. continue;
    32. }
    33. else if (ip.AddressFamily == AddressFamily.InterNetworkV6 && !ResolveHostnamePreferIPv4)
    34. {
    35. ipAddress = ip;
    36. continue;
    37. }
    38. }
    39. // Fallback --> If we could not resolve our prefered ip protocol
    40. if (ipAddress == null)
    41. {
    42. foreach (IPAddress ip in ipHostEntrys.AddressList)
    43. {
    44. ipAddress = ip;
    45. continue;
    46. }
    47. }
    48. }
    49. // Add the hostname or ip address to the history
    50. HostnameOrIPAddressHistory = new List<string>(HistoryListHelper.Modify(HostnameOrIPAddressHistory, HostnameOrIPAddress, 5));
    51. // Traceroute
    52. TracerouteInfo info = new TracerouteInfo
    53. {
    54. IPAddress = ipAddress,
    55. Timeout = Timeout,
    56. Buffer = Buffer,
    57. MaximumHops = MaximumHops,
    58. DontFragement = true
    59. };
    60. sourceToken = new CancellationTokenSource();
    61. Traceroute traceroute = new Traceroute();
    62. traceroute.Trace(info, Traceroute_HopReceived, Traceroute_TraceComplete, Traceroute_UserHasCanceled, sourceToken.Token);
    63. }
    64. catch (SocketException) // This will catch DNS resolve errors
    65. {
    66. MetroDialogSettings dialogSettings = new MetroDialogSettings();
    67. dialogSettings.CustomResourceDictionary = new ResourceDictionary
    68. {
    69. Source = new Uri("NETworkManager;component/Resources/Styles/MetroDialogStyles.xaml", UriKind.RelativeOrAbsolute)
    70. };
    71. await dialogCoordinator.ShowMessageAsync(this, Application.Current.Resources["String_Header_DnsError"] as string, Application.Current.Resources["String_CouldNotResolveHostname"] as string, MessageDialogStyle.Affirmative, dialogSettings);
    72. }
    73. catch (Exception ex) // This will catch any exception
    74. {
    75. MetroDialogSettings dialogSettings = new MetroDialogSettings();
    76. dialogSettings.CustomResourceDictionary = new ResourceDictionary
    77. {
    78. Source = new Uri("NETworkManager;component/Resources/Styles/MetroDialogStyles.xaml", UriKind.RelativeOrAbsolute)
    79. };
    80. await dialogCoordinator.ShowMessageAsync(this, Application.Current.Resources["String_Error"] as string, ex.Message, MessageDialogStyle.Affirmative, dialogSettings);
    81. }
    82. }
    83. private void Traceroute_UserHasCanceled()
    84. {
    85. IsTraceRunning = false;
    86. MessageBox.Show("canceld by user");
    87. }
    88. private void Traceroute_HopReceived(TracerouteArgs args)
    89. {
    90. // Add result
    91. Application.Current.Dispatcher.BeginInvoke(new Action(delegate ()
    92. {
    93. TraceResult.Add(args);
    94. }));
    95. }
    96. private void Traceroute_TraceComplete()
    97. {
    98. IsTraceRunning = false;
    99. }
    100. private void StopTrace()
    101. {
    102. sourceToken.Cancel();
    103. }


    Nun zu meiner Frage:

    Momentan übergebe ich ja für alles eine Action (z.B. wenn ein Hop gefunden wurde), damit ich dem Benutzer live zeige das was passiert und nicht erst nach x-Sekunden das Gesamtergebnis liefere: traceroute.Trace(info, Traceroute_HopReceived, Traceroute_TraceComplete, Traceroute_UserHasCanceled, sourceToken.Token);

    Gibt es auch die Möglichkeit das ganze so zu schreiben, damit ich ein Event abonnieren kann? Also mit Eventhandler und Delegate? Das ganze soll aber asynchron laufen damit die UI nicht blockiert.

    In etwa so...

    C#-Quellcode

    1. Traceroute traceroute = new Traceroute();
    2. traceroute.HopReceived += Traceroute_HopReceived;
    3. traceroute.Trace();
    NETworkManager - A powerful tool for managing networks and troubleshoot network problems!
    Müsste schon gehen, dazu in deinerTraceroute Klasse ein Event deklarieren und bei Bedarf aufrufen Und deinenEventhandler als Async markieren.
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell