Projekt zyklisches Senden und Empfangen von Http Daten

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

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

    Du hast Recht. Die Methode ist aktuell nicht eingetragen. Wird aber wieder rein kommen.

    Vielen Dank für den Tipp mit dem WiFo-Timer. Werde es in den nächsten Tagen mal anschauen.

    Was ist zu kompliziert? Ich möchte es ja ändern und lernen.

    Die Try/Catch kannnich erst einmal heraus nehmen.
    guggemol dies:

    VB.NET-Quellcode

    1. Imports System.IO
    2. Imports System.Net
    3. Public Class Bacnet
    4. Public Property Id As String
    5. Public Property Pid As String
    6. Public Property Plz As Integer
    7. Public Property Ort As String
    8. Public Property Time As Integer
    9. Private WrTimeout As Integer = 1000 'Angaben in ms
    10. Private SrTimeout As Integer = 1000 'Angaben in ms
    11. Private _Data As String
    12. Private _EMessage As String
    13. Private _RMessage As String
    14. Public ReadOnly Property Data() As String
    15. Get
    16. Return _Data
    17. End Get
    18. End Property
    19. Public ReadOnly Property EMessage As String
    20. Get
    21. Return _EMessage
    22. End Get
    23. End Property
    24. Public ReadOnly Property RMessage As String
    25. Get
    26. Return _RMessage
    27. End Get
    28. End Property
    29. Public Sub WdVorhersage()
    30. Dim Url = "http://api.openweathermap.org/data/2.5/forecast?q=" & Ort & ",DE&mode=xml&appid=" & Pid & "&units=metric&lang=de"
    31. Dim Request = WebRequest.Create(Url)
    32. Request.Timeout = WrTimeout
    33. Using Response = Request.GetResponse(), Reader = New StreamReader(Response.GetResponseStream())
    34. _Data = Reader.ReadToEnd()
    35. End Using
    36. End Sub
    37. End Class
    so die richtung.
    Beachte die Namenskonvention mit _-Prefix für private Felder. Public Properties sollten keinen Prefix haben, schon garnet P - da fängt man ja an zu stottern wenn man das liest ;)
    Beachte auch den UsingBlock.
    Und Initialisierungen wie WrTimeout = 1000 sollen nur einmal ausgeführt werden - nicht jedesmal wenn die Klasse was tun soll.
    Beachte auch, dass die Time-Klasse verschwunden ist - dassis Absicht.

    Und wenn du Visual Studio - Empfohlene Einstellungen richtig beherzigt hast, brauchst du nicht Option Strict On über jede Datei zu schreiben.
    Wenn du es aber nicht richtig beherzigt hast, solltest du es doch richtig beherzigen.

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

    Ja traumhaft. Vielen, vielen Dank.
    Das mit Using ist mir das erste Mal in Verbindung mit XML-Verarbeitung bekannt geworden. Da muss ich noch den Vorteil erlesen.
    Viel gelernt...Danke. Ich werde mal den Timer nun noch einbasteln.

    das mit Strict On hatte ich kurzfristig aufgrund der Folgenden Aussage getätigt:

    Daher empfehle ich, für jede Datei händisch die Deppen-Einstellungen wieder zu aktivieren, indem man am Anfang jeder Datei hinschreibt:
    gesagt - getan :)
    werde es mir nochmal in Gänze zu Gemüte führen


    ohne Try/Catch kann EMessage auch raus.

    Jo, das mit dem händisch ist ein Zwischen-Schritt auf das Ziel zu, der nützlich ist, um bei viel Code auf die Grundeinstellungen zu migrieren.
    Nach der Migration ist Strict On ja eine Projekt-Eigenschaft, und braucht nicht weiter in jeder Datei notiert zu sein (schadet aber auch nicht, irritiert nur Korintenkacker wie mich).

    Der Using-Block hat was mit dem Dispose-Pattern ( <- Google-Stichwort) zu tun - es ist eine kürzer und sicherer, als wenn man für jedes disposable Objekt .Dispose aufruft. Wie gezeigt, kann man mehrere Objekte in derselben Using-Deklaration instanzieren - das führt zu knappen, übersichtlichen, wasserdichten Code.

    ja - immer alles rausschmeissen, was raus kann. Aufgeräumten Code lesen ist fast ein Vergnügen,
    So melde mich zurück: Ich habe versucht Informationen zu dem angesprochenen Dispose-Pattern zu bekommen und teilweise auch einige Infos bekommen. Nur ich bezweifle, dass ich es verstanden habe. Es geht wohl schlussendlich um Ressourcenfreigabe, die man vorher belegt. Dann gibt es verwalteter Speicher und nicht verwalteter Speicher - einen Typ muss man explizit freigeben und bei dem Anderen nicht. Da ich in deinem Codevorschlag keine Erwähnung von Disposable o.Ä. finde, gehe ich davon aus, dass man es nicht explizit freigeben muss oder leitet man die Freigabe mit dem Using-Block ein?!
    Für einen Fachinformatiker ist das vermutlich einfach, aber ich tue mich da schwer. Fakt ist, dass ich im Debug-Modus sehe, dass der Speicher freigegeben wird.
    Wieso hast du die

    VB.NET-Quellcode

    1. .Closed
    Anweisungen nicht mit im Using-Block? MSDN hat es ihren Beispielen überall enthalten.
    In dem Zuge habe ich an dem Projekt weitergearbeitet und versucht das USING mit meiner XML-Auswertung zu paaren (versucht Dispose anzuwenden) und noch ein paar Anpassungen durchgeführt. Ich werde das XML nochmal umarbeiten. Aus der PHP-Sprache kenne ich Switch/Case-Anweisungen. Ich vermute, dass es solch Technik auch bei VB.net gibt und mir sagt mein Gefühl, dass das die bessere Variante ist. Natürlich bin ich für weitere Vorschläge offen.

    Zusätzlich bin ich deiner Empfehlung gefolgt und habe den Timer als Form eingefügt und das Tick-Event mit auf den Handler vom Button gehangen. Kann man das so machen oder ist es nicht elegant, doof ?
    Irgendwie habe ich noch das Gefühl, dass das Kompilieren und Verwenden auf einen anderen Rechner noch Probleme bereiten wird.

    Abschließend möchte ich mich für die Geduld, Ausdauer und die Hilfe nochmals herzlichst bedanken und den Code anhängen.

    bacnet.vb
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System
    2. Imports System.IO
    3. Imports System.Net
    4. Imports Inneasoft.BACnet
    5. Imports System.Xml
    6. Public Class Bacnet
    7. Public Property Id As String
    8. Public Property Pid As String
    9. Public Property Plz As Integer
    10. Public Property Ort As String
    11. Private _LastTime As String
    12. Private _AT As String
    13. Private _Data As String
    14. Private _Message As String
    15. Private _WrTimeout As Integer = 1000 'Angaben in ms
    16. Private Request As WebRequest
    17. Private Response As WebResponse
    18. Private Stream As Stream
    19. Private Reader As StreamReader
    20. Public ReadOnly Property Data() As String
    21. Get
    22. Return _Data
    23. End Get
    24. End Property
    25. Public ReadOnly Property Message As String
    26. Get
    27. Return _Message
    28. End Get
    29. End Property
    30. Public ReadOnly Property AT As String
    31. Get
    32. Return _AT
    33. End Get
    34. End Property
    35. Public ReadOnly Property LastTime As String
    36. Get
    37. Return _LastTime
    38. End Get
    39. End Property
    40. Public Sub WdAktuell()
    41. Dim Url = "http://api.openweathermap.org/data/2.5/weather?q=" & Ort & ",DE&mode=xml&appid=" & Pid & "&units=metric&lang=de"
    42. 'Instanzieren einer Verbindung
    43. Request = WebRequest.Create(Url)
    44. Request.Timeout = _WrTimeout
    45. Using Response = Request.GetResponse()
    46. Reader = New StreamReader(Response.GetResponseStream())
    47. _Data = Reader.ReadToEnd()
    48. If Reader.EndOfStream = True Then
    49. If Data.Length > 1 Then
    50. _Message = " Daten erfolgreich empfangen!"
    51. End If
    52. End If
    53. Reader.Close()
    54. Response.Close()
    55. End Using
    56. XMLReader()
    57. End Sub
    58. Private Sub XMLReader()
    59. Using XmlReadSystem As XmlReader = System.Xml.XmlReader.Create(New StringReader(Data))
    60. XmlReadSystem.ReadToDescendant("temperature")
    61. XmlReadSystem.MoveToAttribute(0)
    62. _AT = XmlReadSystem.Value
    63. XmlReadSystem.ReadToNextSibling("lastupdate")
    64. XmlReadSystem.MoveToAttribute(0)
    65. _LastTime = Convert.ToDateTime(XmlReadSystem.Value).ToString
    66. XmlReadSystem.Close()
    67. End Using
    68. End Sub
    69. End Class



    AWB.vb
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System
    2. Imports System.IO
    3. Imports System.Net
    4. Imports System.Timers
    5. Imports Inneasoft.BACnet
    6. Public Class AWB
    7. Private VarTimer As Integer
    8. Private Wetter As New Bacnet
    9. Private RohWerte As String
    10. Private IsOnline As Boolean
    11. Public Sub New()
    12. ' Dieser Aufruf ist für den Designer erforderlich.
    13. InitializeComponent()
    14. End Sub
    15. Private Sub btnXml_Click(sender As Object, e As EventArgs) Handles btnXml.Click
    16. MessageBox.Show(RohWerte, "XML-Rohdaten", MessageBoxButtons.OK)
    17. End Sub
    18. Private Sub btnInfo_Click(sender As Object, e As EventArgs) Handles btnInfo.Click
    19. Infos.ShowDialog()
    20. End Sub
    21. Private Sub btnBacstart_Click(sender As Object, e As EventArgs) Handles btnBacstart.Click, Timer.Tick
    22. btnBacstart.Enabled = False
    23. btnBacStop.Enabled = True
    24. Timer.Enabled = True
    25. VarTimer = Convert.ToInt16(tbAktZeit.Text) * 60 * 1000
    26. If VarTimer <= 10000 Then
    27. Exit Sub
    28. Else
    29. tbLastTime.Text = System.DateTime.Now.ToString
    30. Wetterinstanz()
    31. If IsOnline = True Then
    32. Else
    33. Bacnetserver()
    34. End If
    35. End If
    36. End Sub
    37. Private Sub btnBacStop_Click(sender As Object, e As EventArgs) Handles btnBacStop.Click
    38. BACnetAPI.Uninitialize()
    39. Timer.Enabled = False
    40. RohWerte = Nothing
    41. btnBacstart.Enabled = True
    42. btnBacStop.Enabled = False
    43. End Sub
    44. Private Sub Wetterinstanz()
    45. Wetter.Pid = tbPid.Text
    46. Wetter.Ort = tbOrt.Text
    47. Wetter.WdAktuell()
    48. If String.IsNullOrEmpty(Wetter.Message) Then
    49. btnXml.Enabled = False
    50. Else
    51. tsStatus.Text = Wetter.Message
    52. tsStatus.ForeColor = Color.Lime
    53. btnXml.Enabled = True
    54. End If
    55. tbAt.Text = Wetter.AT
    56. tbLastAkt.Text = Wetter.LastTime
    57. RohWerte = Wetter.Data
    58. End Sub
    59. Private Sub Bacnetserver()
    60. Dim Server As New BACnetServerDevice
    61. Dim AV1 As BACnetServerObject
    62. BACnetSettings.Port = CType(tbPort.Text, Integer)
    63. Server.AddObject(New BACnetServerAnalogValue(1, "Aussentemperatur"))
    64. Server.Id = CType(tbBid.Text, Integer)
    65. Server.Name = tbBn.Text
    66. BACnetAPI.Initialize()
    67. BACnetAPI.SetServerDevice(Server)
    68. IsOnline = BACnetAPI.IsInitialized
    69. AV1 = Server.GetObject(BACnetObjectType.ANALOG_VALUE, 1)
    70. AV1.Value = Wetter.AT
    71. AV1.Description = "aktuelle Aussentemperatur"
    72. End Sub
    73. End Class


    Welchen Unterschied gibt es zwischen der CType-Methode und der Convert.To-Methode?
    Mir scheint, du hast dich mit zuvielen Details belastet, und dabei die goldenen Regeln nicht mitbekommen:
    1. Es gibt Datentypen, deren Objekt-Instanzen der GarbageCollector nicht sauber aufräumen kann - diese Objekte müssen explizit aufgeräumt werden. (Das Gefasel von verwaltet / nicht verwaltet habich auch nicht sicher verstanden - evtl. bedeutet das auch nichts anderes, als das hier gesagte: kanner aufräumen oder nicht)
    2. Solche Datentypen sollten IDisposable implementieren, denn der Aufruf .Dispose() ist ganz allgemein der Aufruf des expliziten Aufräumens
    3. Ob ein Datentyp IDisposable implementiert, kannste im ObjectBrowser ( <- folge dem Link!! ) nachgucken.
    4. Wenn dem so ist, ist bei Objekten dieses Datentyps dringend geraten, sie nach Verwendung zu disposen.
    5. Disposen kann man diese Objekte durch Aufruf von .Dispose(), aber eleganter und sicherer ist der Using-Block.

    Fahrstuhllicht schrieb:

    Wieso hast du die .Closed-Anweisungen nicht mit im Using-Block? MSDN hat es ihren Beispielen überall enthalten.
    Braucht man nicht. Der Using-Block disposed das Objekt, d.h., es wird aufgeräumt. Zum Aufräumen gehört bei Streams definitiv dazu, dass sie geschlossen werden.

    Beachte: MSDN-CodeBeispiele sind zwar nie falsch, aber in vielen vielen Fällen sind sie weit davon entfernt, gut zu sein.
    Also was du da findest, funktioniert zwar, und man kann Funktionsweisen daraus lernen - es ist aber meist (wage ich zu behaupten) unnötig umständlich.
    Oder anders: Für Copy&Paste ist MSDN keine wirklich gute Quelle.



    Abschliessend noch Genörgel wegen Benamung - weisst ja:
    Nomen est Omen!

    WdAktuell() ist kein Name für eine Methode (Es ist ühaupt kein Name - "WdAktuell" - was soll das sein, ein "WdAktuell"??). Eine Methode tut etwas, und soll so heissen wie was sie tut - hier scheint mir LoadCurrentWeatherData() oder sowas angemessen, denn wenn ich recht verstehe lädt die Methode aktuelle Wetter-Daten und hinterlegt sie der Data-Property.

    Ganz ähnlich der Name XmlReader(). "XmlReader" ist keine Tätigkeit, sondern XmlReader ist eine Klasse des Frameworks. Keine gute Idee, eine Tätigkeit so zu benennen - da kommt man im Leben nicht drauf, dass das eine Methode ist, die Temperatur und LastUpdate aus der Data-Property extrahiert und als Properties verfügbar macht.
    Ich würde die Methode ProcessData() nennen, denn das ist was sie tut: Sie verarbeitet (engl: "to process") die in Data liegenden Daten.

    Das AWB ist mir zu umfangreich, ums zu behühnern. Nur soweit:
    "AWB" - was soll das sein? Lässt sich kein Name dafür finden, den man auch versteht?
    Und bei Forms präferiere ich einen Prefix zu vergeben, etwa frmWeatherApp, oder auch einfach frmMain oder sowas.
    Dann weiss man wo der Code steht, und ein Form ist ein sehr spezieller und sehr reichhaltiger Code-Kontext - für den Leser unerlässlich, das zu wissen.

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