[C#] Wie Post Requests teilw. mit multipart-Formular und Queue

  • Moin liebes WHF,

    ich helfe einem Kumpel bei einem kleinen Projekt aus und da dort leider eine unsexy Mischung aus proprietäre Hardware, komische Software und Windows herumköchelt, muss ich mich leider da beugen und in die C# und die wunderliche Microsoft-Welt eintauchen.

    Ich will folgendes erreichen:

    • HTTP Post Request, teilweise mit Datei-Upload, abschicken.
    • Muss asynchron im Hintergrund laufen.
    • Darf auf KEINEN Fall den Haupt-Thread blockieren.
    • Die Queue sollte persistent sein, damit nach einem Programm-Neustart keine Jobs verloren gehen.
    • Sollte der Post Request failen (5xx Fehler, keine Konnektivität), muss der Jobs mit zeitlichem Versatz später versucht werden.

    Kennt jemand da eine relativ fertige Lösung?

    Ich hab bisher nur das Uploaden hingefummelt und eigentlich gedacht, das wäre async, aber dennoch blockiert der Haupt-Thread, wenn das Posten an sowas wie No Route To Host scheitern.

    Ich kann mir nicht vorstellen, dass es sowas nicht bereits als Library oder so geben sollte.

    Danke für soliden Input.

    PS: NUTZ $andereProgrammierspracheOderAnderesBetriebsystem GEHT NICHT. Das habe ich schon ausgiebig evaluiert...

  • Das ist keine Browser-Webanwedung-Kiste. Das ist rein Hardware über Software ansprechen. Nur ich brauch halt noch HTTP wegen paar anderen Sachen, die die Hauptanwendung nicht blockieren darf, aber zuverlässig arbeiten muss.

  • Schau dir mal ThreadPool.QueueUserWorkItem an für die asynchronen Sachen. Dann ist nur nicht garantiert, dass sie in der gleichen Reihenfolge ausgeführt werden. Als Ausfallsicherung kannst du alle aktuellen Jobs in ne Datei speichern. Wenn der Upload gestartet wird, markierst du ihn in der Datei als gestartet bzw fehlgeschlagen (mit Uhrzeit/Datum), wenn er erfolgreich ist löschst du ihn. Du kannst bei einem Absturz oder auch von Zeit zu Zeit prüfen, in welchem Zustand das Programm ist und alte Jobs neustarten

    Spoiler anzeigen


    Haupt-Laptop:
    Dell Vostro 3560 - i7-3632QM, 6GB
    Rechenknechte:
    Lenovo - i5, 4GB
    Medion - Pentium Dual Core, 3GB
    IBM T60 - Core Duo, 2GB
    Lenovo T400 - Core2Duo, 2GB
    Server:
    Sony - Pentium M, 512MB
    Unbenutzt:
    Noname - Celeron D, 1GB

  • Okay, ThreadPool Worker klingt nicht verkehrt! Ich schau es mir mal an. So einen ähnlichen Ansatz mit Datei schreiben und schauen, ob die es noch gibt, hatte ich auch schon in Erwägung gezogen.

  • Wenn das ganze keine besonderen Performanceanforderungen hat, kannst dir für die Datei mal Serialisierung anschauen, das geht auch mit den Listen- und Stacktypen.

    Spoiler anzeigen


    Haupt-Laptop:
    Dell Vostro 3560 - i7-3632QM, 6GB
    Rechenknechte:
    Lenovo - i5, 4GB
    Medion - Pentium Dual Core, 3GB
    IBM T60 - Core Duo, 2GB
    Lenovo T400 - Core2Duo, 2GB
    Server:
    Sony - Pentium M, 512MB
    Unbenutzt:
    Noname - Celeron D, 1GB

  • Habe sehr wenig Erfahrung mit C#/.NET, etwas Senf möchte ich trotzdem dazugeben, aber ich hab mich mal länger mit In-Memory Thread Pool Queues auseinandergesetzt: Die Dinger sind für viele gleichzeitig arbeitende Threads optimiert, mit komplexen Locking-Mechanismen, CPU-Cache-Optimierung etc. Wenn solche Queues die bei jedem Request in Dateien serialisiert verliert man praktisch alle genannten Vorteile, weil da immer ein globales Lock genommen werden muss. Du willst die Requests ja eigentlich nicht im Memory vorhalten, sondern auf einem persistenten Speicher.

    Darum: Da Persistenz bei dir wichtiger scheint als Performance (und dafür sind solche Queues häufig optimiert) würde meinen Fokus viel eher auf Persistenz getrimmte Messaging-Queues widmen, wie z.B. Rabbit MQ. Selbst eine kleine Datenbank (SQLite z.B. mit einem Thread der INSERT macht, und den Worker-Threads die SELECT/DELETE machen) dafür zu missbrauchen funktioniert in der Regel relativ robust. Garantiert nicht die schnellste Lösung, dafür robust und persistent, und vermutlich weniger Gefrickel als eine In-Memory-Queue manuell in Dateien zu dumpen und sicher zu stellen dass die synchronisiert bleiben.

    Einmal editiert, zuletzt von gandro (6. Februar 2015 um 19:17)

  • Ja, mir geht es eher um Persistenz als um Geschwindigkeit. Ich schau mir auch mal Rabbit MQ et cetera oder eventuell sqlite. Das würde sogar etwas Flexibilität ins Spiel bringen. Danke! :)

  • Shameless self-bump.

    Ich hab mir Rabbit MQ angeschaut, habe mich allerdings dann doch gegen eine persistente Queue entschieden.
    Eine normale Queue tut ihren Zweck und das Datenpaket, was nicht untergehen soll, wird auf eine andere Weise wieder hochgeschoben. (Gibt eine "Outbox", die kann manuell nach einer Störung angestoßen werden.)

    ThreadPool läuft auch mega. Vielen Dank für den Tipp nochmals!

    multipart war allerdings ziemlicher Pain in the Ass. Ich durfte mir das multipart-Dokument selbst zusammenbauen und bin erstmal über paar Eigenheiten von C#/.net gestolpert:

    • write() auf einen StreamWriter mit einem Byte-Array schreibt nicht das Byte-Array, sondern "Byte[]"
    • BinaryWriter schreibt ohne konkrete Längenangabe Strings kodiert mit Länge plus Nutzlast in den Stream. Hier kam ein Workaround mit String zu byte[] Array zur Hilfe.

    Ansonsten steht alles und nochmals Danke für euren Input!

    Case closed.

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!