Laden...

Fehler Status bei Nutzung von PostAsync() abfangen

Erstellt von Marcel vor 8 Jahren Letzter Beitrag vor 8 Jahren 4.804 Views
M
Marcel Themenstarter:in
210 Beiträge seit 2005
vor 8 Jahren
Fehler Status bei Nutzung von PostAsync() abfangen

Hallo.

Ich habe eine statische Methode zum hochladen von einer Datei und weiteren Informationen. Das Hochladen geschieht per PostAsync() aus der HttpClient-Klasse.

Die Anfrage soll sich mittels eines Authentifizierungstokens beim Server gepüft werden. Sende ich einen ungültigen Token, so bekomme ich korrekter Weise vom Server einen 403 zurück. Soweit so gut.

Meine Schwierigkeit bekomme ich nun dabei diesen 403 auch innerhalb meiner Windowsanwendung zur greifen um ihn anzuzeigen. Beim der unten stehenden Methode versuche ich den Status abzufragen und dann auszugeben, allerdings kommt er nie über ".. client.PostAsync(url, formData).Result;" hinweg!

Die Methode loadFromDownloadDirToURL() wird beim Aufrufer innerhalb einer try catch Anweisung ausgeführt die eine Ausnahme anzeigt mit der Beschreibung. "Es ist mindestens ein Fehler aufgetreten"?!

Diese Mechanik mit asynchronen Aufrufen ist mir relativ neu und ich komme nur schwer damit zurecht. Wenn ich debugge kommt er nie an die Stelle unterhalb dieses Aufrufes.

Was mache ich falsch? Bitte um Hilfestellung.


public static void loadFromDownloadDirToURL(string url, string fileName, string token)
        {
            // Datei einlesen
            byte[] file = IOMgmt.readBytesFromDownloadDir(fileName);          

            // Formulardaten
            MultipartFormDataContent formData = new MultipartFormDataContent();                    
            formData.Add(new StringContent(Convert.ToBase64String(file)), "file");
            formData.Add(new StringContent(fileName), "filename");
            formData.Add(new StringContent(token), "token");                      

            HttpClient client = new HttpClient();            
            HttpResponseMessage response = client.PostAsync(url, formData).Result;
            if (!response.IsSuccessStatusCode)
            {
                throw new Exception(response.StatusCode.ToString());
            }            
        }

16.834 Beiträge seit 2008
vor 8 Jahren

Mit dem .Result untertdrückst Du Fehler und kannst einen Deadlock auslösen.
Wieso verwendest Du den async/await Pattern nicht einfach richtig? Ja, kann gut sein, dass man sich mit dem Pattern vertraut machen muss 😃 Aber dafür gibts eine sehr gute Dokumentation in der MSDN.

Statische Methode sieht auch nicht gerade gut überlegt aus 😉

M
Marcel Themenstarter:in
210 Beiträge seit 2005
vor 8 Jahren

Diese Mechanik mit asynchronen Aufrufen ist mir relativ neu und ich komme nur schwer damit zurecht.

Ich würde mich über ein Bespiel mit einer besseren Version (angelehnt an meine) sehr freuen 😃

16.834 Beiträge seit 2008
vor 8 Jahren

Naja, ich werd Dir jetzt nicht den Code schreiben; mit Sicherheit nicht.
Wieso nicht einfach die Doku lesen, wo es gut erklärt ist?

M
Marcel Themenstarter:in
210 Beiträge seit 2005
vor 8 Jahren

Man soll mir auch nicht mein komplettes Programm schreiben sondern nur den Teil mit dem Upload anhand von Besipielen erläutern, thats all

OK ich seh schon...ich versuch mal Hilfe in anderen Foren zu finden.

16.834 Beiträge seit 2008
vor 8 Jahren

Da kann ich nur sagen: viel Erfolg 😃

Hätte ich mehr Eigeninitiative gesehen, dann hätte ich Dir trotz [Hinweis] Wie poste ich richtig? Punkt 4 nen Code Beispiel genannt.
Aber Du hast leider nicht mal auch nur den Hauch des Interesses (Antwort 2 Min nach meinem Beitrag) die Doku zu lesen gezeigt. Sieht eher nach "abwälzen" aus und ich lass mich nicht ausnutzen. Schade drum.

M
Marcel Themenstarter:in
210 Beiträge seit 2005
vor 8 Jahren

Herr Gott, was ist denn hier los?!
Da stellt man eine Frage und wird derart abweisend behandelt. Ich würde hier nicht posten wenn ich nicht schon den ganzen Tag rumsurfen würde nach einer Lösung. Vielleicht such ich an den falschen Stellen oder kapier es halt noch nicht, kann alles sein. Aber eine Antwort wie "Such die Lösung selbst und dann wenn du sie kennst kannst hier nochmal posten" ist auch reltiv wertlos.

16.834 Beiträge seit 2008
vor 8 Jahren

Davon abgesehen, dass ich Dein Zitat weder wörtlich noch inhaltlich geschrieben habe, habe ich Dich auf die mehr als ausführliche Dokumentation der MSDN (Asynchrone Programmierung mit Async und Await (C# und Visual Basic)) verwiesen - freundlich und sachlich.
Dort ist eine ausführliche Beschreibung, Prinzipien und ein vollständiges Beispiel enthalten.
Ich kann mir - sorry - wirklich nicht vorstellen, dass man diese Seite nicht findet.

Statt den Rat anzunehmen hast Du direkt, keine 2 Minuten später ein Beispiel "gefordert".
Ich erkenn hier also weder Initiative noch Wille; wieso sollte ich Dir dann den Code schreiben, wenn die Gegenseite kein wirkliches Interesse hat sondern - gefühlt - die Arbeit auf das Forum abladen will?
Genau so hört sich auch der Satz "geh ich halt wo anders hin" an.

Mir vorzuwerfen, dass ich nicht helfen wollen würde, naja... 😉
Ich helfe gerne - ich denke, dass das mehr als offensichtlich ist. Aber nicht, wenn jemand nur den fertigen Code will. Ob das Tatsache ist oder nur falsch ausgedrückt... liegt nicht in meiner Hand.
Zudem hab ich Dir eigentlich auch schon gesagt, warum Du keinen Fehler bekommst - im ersten Post von mir hier (Result unterdrückt).

M
Marcel Themenstarter:in
210 Beiträge seit 2005
vor 8 Jahren

Also die Sache ist die:

Ich möchte versuchen meinen Quellcode möglichst simpel zu halten. Weder mir noch einem Kollegen möchte ich wegen eines eigentlich simplen uploads einer Datei, dieses doch - wie ich finde - recht komplizierte Konstrukt von "async und wait" aufzwingend. Stichwort Wartbarkeit des Quelltextes.

Ich nutze zwar diese asynchrone Methode "PostAsync(url, formData)" aber eigentlich würde ich viel lieber synchron arbeiten. Deswegen hatte ich nach einigen Recherchen auf Seiten wie z.B. dieser Seite versucht dan Aufruf synchron zu machen mit eben dm ".Result" am ende der Funktion.

Dies führt zum oben beschriebenen Problem. Es wird dabei durchaus eine Exception ausgelöst, nur keine in der ich den StatusCode (403) abfragen könnte.

In der oberen Variante kann ich die Formulardaten bequem per MultipartFormDataContent-Objekt erzeugen und an die Funktion übergeben. Ich habe leider keine vergleichsweise simple Vorgehensweise im Internet finden können um die Formulardaten zu senden.

Eventuell weiß ja jemand ein alternative Vorgehensweise, die ohne asynchrone Funktion auskommt?!

S
322 Beiträge seit 2007
vor 8 Jahren

Hallo Marcel,

bei einer Async Methode werden im Falle eines Fehlers immer eine AggregateException geworfen. Die eigentliche Ursache steckt aber in der InnerException der AggregateException:

Beispiel ungetestet:


try
{
    loadFromDownloadDirToURL(...);
}
catch (AggregateException ex)
{
    MessageBox.Show(ex.InnerException);
}

D.h. schau mal in die InnerException ob du da mehr Infos rauslesen kannst...

Grüße
Steffen

16.834 Beiträge seit 2008
vor 8 Jahren

bei einer Async Methode werden im Falle eines Fehlers immer eine AggregateException geworfen.

Das stimmt leider nicht 😃
Auch zeigst Du leider keine korrekte Anwendung des async/await Patterns

M
Marcel Themenstarter:in
210 Beiträge seit 2005
vor 8 Jahren

Hallo Steffen.

Ich habe das mal versucht und der InnerException ist leider auch nicht der StatusCode des Servers. In diesem Falle wird eine "TaskCanceledException" geworfen un dder Text der InnerException lautet > Fehlermeldung:

Error while copying content to a stream. Hier mal eine Ausschnitt as dem Log:

09:23:15.657> bei System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
bei System.Threading.Tasks.Task1.GetResultCore(Boolean waitCompletionNotification) bei System.Threading.Tasks.Task1.get_Result()
bei LlPortalDesigner.IOMgmt.loadFromDownloadDirToURL(String url, String fileName, String token) in c:\Users\XGWSWGM\Documents\Visual Studio 2013\Projects\LlWebService\LlPortalDesigner\IOMgmt.cs:Zeile 101.
bei LlPortalDesigner.MainForm.startUpload() in c:\Users\XGWSWGM\Documents\Visual Studio 2013\Projects\LlWebService\LlPortalDesigner\MainForm.cs:Zeile 277.
09:23:15.610> Fehler beim Hochladen der Projektdateien: Error while copying content to a stream.
09:23:15.610> Fehler beim Hochladen der Projektdateien: Mindestens ein Fehler ist aufgetreten.

Hinweis von Coffeebean vor 8 Jahren

Bitte benutze die richtigen Code-Tags [Hinweis] Wie poste ich richtig? Punkt 6

16.834 Beiträge seit 2008
vor 8 Jahren

Da Du die System.Net.Http Klasse verwendest vermute ich, dass Du entweder eine Windows 8(.1) oder eine Universal App verwendest.
Dazu passt auch der Link, den Du gepostet hast.

Jetzt ist es im App/UWP-Umfeld so, dass asynchrone Programmierung kein Kann-Zustand ist, sondern ein Muss-Zustand. Da hilft auch kein Bockig-sein oder mit den Füßen auf den Boden stampfen.
Implementierst Du nichts async oder nicht richtig, dass schießt der AppScheduler die App ab (und das ist auch gut so).
Das kannst Du übrigens auch in der Dokumentation nachlesen bzw. wird das auch bei zahlreichen Channel9 Videos zum Einstieg in die App-Welt ausdrücklich gesagt. Man muss sich nur die Mühe geben und mal zuhören können 😉

Die Aussage

Ich nutze zwar diese asynchrone Methode "PostAsync(url, formData)" aber eigentlich würde ich viel lieber synchron arbeiten.

ist also leider keine Option.

Du wirst Dich zwangsläufig mit async/await und korrekter Task-Implementierung beschäftigen müssen, wenn Du in diesem Umfeld etwas programmieren möchtest - ob Du willst oder nicht.
Deswegen wirst Du auch normalerweise/meistens in den Namespaces für diese Zielapplikationen nur noch asynchrone Implementierungen finden.

public async Task<String> loadFromDownloadDirToURL(string url, string fileName, string token)
{
    // Datei einlesen
	
	// keine Ahnung was IOMgmt sein soll; dem Namen nach liest es irgendwo (Extern) Bytes und _muss_ daher asynchron implementiert sein
    byte[] file = await IOMgmt.readBytesFromDownloadDirAsync(fileName);

    // Formulardaten
    MultipartFormDataContent formData = new MultipartFormDataContent();
    formData.Add(new StringContent(Convert.ToBase64String(file)), "file");
    formData.Add(new StringContent(fileName), "filename");
    formData.Add(new StringContent(token), "token");

	// Ebenfalls externer Zugriff (Web) und damit asynchron Pflicht
    HttpClient client = new HttpClient();
    HttpResponseMessage response = await client.PostAsync(url, formData);
    if (!response.IsSuccessStatusCode)
    {
        throw new Exception(response.StatusCode.ToString());
    }
	
	// hier kein await obwohl async, weil Task durchgereicht wird
	return response.Content.ReadAsStringAsync();
}

Und jetzt endlich mit Tasks beschäftigen.

M
Marcel Themenstarter:in
210 Beiträge seit 2005
vor 8 Jahren

Das ich nicht asynchron arbeiten möchte hat eben einige Gründe:

  • Garnicht notwendig an der Stelle
  • Wartbarkeit nur möglich wenn ich und mindestens ein Kollege sich damit auseinandersetzen
  • Fehlerkorrektur aufgrund fehlender Server Status Codes unnötig erschwert
  • Erhöhte Entwicklungszeit durch Einarbeitung in - für mich/uns - neue Technologien
    ..und es hat nicht den Grund:
  • Ich habe kein Bock mich in ein neues Thema einzuarbeiten.

Aber las uns doch lieber fachlich diskutieren. Ich habe mir nämlich mittlerweile durchaus diverse Seiten mit diesem Thema angeschaut. In deiner Version mit den async und await Markern bekomme ich ich bei mir die Compiler-Meldung:

"Da es sich hierbei um eine asynchrone Methode handelt, muss der Rückgabetyp den Wert 'string' anstelle von Task<string> aufweisen."

16.834 Beiträge seit 2008
vor 8 Jahren

Interessante Ansichten...

Also Du kannst Dich da ruhig im Kreis drehen oder bockig stellen; aber bei Apps ist Async nun mal per System-Design notwendig und pflicht, sonst wird die App abgeschossen. Da hilft es auch nicht mit "nicht notwendig" zu argumentieren oder für "beendet" erklären.
Akzeptier diese Tatsache oder lass es halt bleiben. Dann muss man halt zur Not die App Programmierung auslagern. 🤔 Alternativ einen Beschwerdebrief verfassen oder ein Feature Request für synchrone Umsetzungen in Windows Apps einreichen.
Hilft halt der Problemlösung nicht. Wie es korrekt geht hab ich Dir jetzt sogar als Snippet gegeben.
Du hast fachlich jetzt alles was Du brauchst, auch wenn Du es irgendwie nicht ganz verstehen willst.

Und dass man als Entwickler hin und wieder sein Wissen auffrischen und neue Technologien erlernen muss; das ist eigentlich selbstverständlich und gehört in die Ressourcenplanung.

M
Marcel Themenstarter:in
210 Beiträge seit 2005
vor 8 Jahren

Ich glaube du verstehst mich einfach nicht. Ich entwickle eine normale Windows Form Anwendung und in diesem konkreten Fall ist es egal ob das Formular mal ne Sekunde still steht weil Deteien hochgeladen werden. Darauf basiert meine Aussage: "Es ist garnicht notwendig".

Aber wir machen den Thread hier am besten zu denn ich habe es nun synchron gelöst (und es funktioniert ganz wunderbar) und fertig.

16.834 Beiträge seit 2008
vor 8 Jahren

Dann solltest Du das mal sagen (was man nach 10 Jahren im Forum erwarten kann), denn der Link den Du gepostet hast, ist halt Windows Phone.
In der Windows Forms Namespace hast Du auch Methode, die nicht async sind. Nimm halt die.

Hätte hier einiges gespart.