Laden...

Null-Reference Exception nicht nachvollziehbar

Erstellt von CoderboyPB vor 4 Jahren Letzter Beitrag vor 4 Jahren 2.214 Views
C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren
Null-Reference Exception nicht nachvollziehbar

Hallo, ich arbeite mit TweetSharp und das Senden von Textbeiträgen klappt auch.

Nun bekomme ich aber bei folgendem Funktionsaufruf eine

Fehlermeldung:
System.NullReferenceException: "Object reference not set to an instance of an object."


using (var stream = new FileStream(randomPicture, FileMode.Open))
            {
                var dictionary = new Dictionary<string, Stream>();
                dictionary.Add("Gundel Gaukeley", stream);
                Console.WriteLine(Message);

                ts.SendTweetWithMedia(new SendTweetWithMediaOptions
                {
                    Status = Message,
                    Images = dictionary
                }, (tweet, response) =>
                {
                    _status = response.StatusCode;
                });
            }

Wie so oft taugen die Exceptions mal wieder nicht mehr, als man sie weit werfen kann, denn natürlich sagt sie NICHT, um welche Instanz es sich handelt ...

Ich habe es bewusst in Grundlagen gepostet, denn wahrscheinlich ist es irgend so ein Mist, wo ich mich dann selber drüber ärgere, wenn ich drauf gestoßen werde ...

Kann mir hier irgend jemand sagen, was Visual Studio da hat?

301 Beiträge seit 2009
vor 4 Jahren

I smell side effects. Von der Hälfte des Codes ist vollkommen unklar warum du ihn brauchst.

C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren

Och fuck, jetzt ist die Consolen Ausgabe wieder mit reingerutscht, dabei wollte ich damit nur prüfen, ob Message einen Wert hat.

Die beiden Zeilen mit dem Dictionary, kann man auch direkt in die SendMediaTweetOptions packen, hatte ich auch schon, aber wie das so ist, bei der Fehlersuche: Man lässt nichts unversucht, also eben auch dieses Dictionary separat zu erzeugen ...

C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren

Ich habe alles überprüft:
Message, das Dictionary, die Inhalte des Dictionaries, und ts (der TwitterService)

Nichts davon ist Null. VS hat keinerlei Recht, hier ne NullException zu werfen !!!!

301 Beiträge seit 2009
vor 4 Jahren
  • Möglicherweise ist dein Stream irgendwo schon disposed wo er noch benötigt wird
  • Was sagt die Doku zur Verwendung der Methode?
  • Ist die Methode Synchron ( void ?! )
  • Wann wird die function im zweiten step ausgelöst?
  • Kann es sein das die Response null ist?

Ich fürchte wir können dir nur schwer beim debuggen helfen ohne dein Projekt zu kennen.

Wenn die Methode nicht synchron sein sollte würde ich darauf tippen das der Stream noch vor Verwendung von der Tweetmethode disposed wurde. Aber ist nur geraten

Btw: Gibt es sowas wie Stacktraces. Wenn der Stack sagt die Exception kommt von außerhalb deines Codes dann übergibst du entweder was falsches ( -> Doku ) oder es gibt nen Bug in dem Fraemwork

16.806 Beiträge seit 2008
vor 4 Jahren

Emtionen am Forum oder am Code frei zu lassen, hat jedenfalls keinen Sinn.
Daher auch den völlig fehlplatzierten Titel editiert.

Nichts davon ist Null. VS hat keinerlei Recht, hier ne NullException zu werfen !!!!

  1. Visual Studio wirft keine Exceptions, sondern die Runtime. Visual Studio ist ein Editor.
  2. Im Code liegt die Wahrheit.

denn natürlich sagt sie NICHT, um welche Instanz es sich handelt ...

Es kann keine Instanz angegeben werden, da sie ja nicht mal existiert. Daher auch der Null-Fehler.

Kann mir hier irgend jemand sagen, was Visual Studio da hat?

Visual Studio hat gar nichts. Löst ja auch nicht die Exception aus.
Aber die Runtime findet eben etwas, worauf sie zugreifen will, aber null ist.

Spätestens mit einem if an jeder Stelle und einer manuellen Null Prüfung findest Du es raus.
Wenn Du gerne mit neuen Features arbeitest, dann verwende Tutorial: Express your design intent more clearly with nullable and non-nullable reference types.
Dann kannst Du sowas schon zur Compile-Zeit identifizieren.

Alternativ log den StackTrace, wie es die Basics von .NET bereits empfehlen.

C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren

So, habe jetzt rausgefunden, dass der Stream ne TimeOutException wirft, aber wie kann ich die verhindern?

Ich kann das ja schlecht Async machen, denn das Ganze unterliegt einem StrategyPattern, und dann hätte ich zwei verschiedene Signaturen.

Oder soll ich die andere Klasse (Wo nur Text gesendet wird) dann 'Pseudo Async' machen, damit beide Signaturen gleich sind?

16.806 Beiträge seit 2008
vor 4 Jahren

Jede IO Operation sollte Async sein. Jede.

6.911 Beiträge seit 2009
vor 4 Jahren

Hallo CoderboyPB,

(Wo nur Text gesendet wird) dann 'Pseudo Async' machen Task.FromResult(TResult) Method hilft dir hierbei.


public Task<string> FooAsync()
{
    string result = // ...

    return Task.FromResult(result);
}

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren

habe jetzt folgendes, welches ein Fehler erzeugt, weil http.GetAsync() etwas mit Http: übergeben bekommen haben will.


using (var httpClient = new HttpClient())
            {
                HttpResponseMessage response = await httpClient.GetAsync(new Uri(randomPicture));
                if (!response.IsSuccessStatusCode)
                {
                    throw new Exception(response.ReasonPhrase);
                }

                Stream stream = await response.Content.ReadAsStreamAsync();
                var tweet = new SendTweetWithMediaOptions
                {
                    Status = Message,
                    Images = new Dictionary<string, Stream>
                        {
                            { "Gundel", stream }
                        }
                };

                ts.SendTweetWithMedia(tweet,(t, r) =>
                {
                    _status = r.StatusCode;
                });
            }

Statt HttpClient muss da irgendwas mit einem lokalen Filezugriff hin, aber hier bin ich überfordert.

Mein Ansatz wäre


public async Task SendAsync(string Message, TwitterService ts)
        {
            var imageFiles = Directory.GetFiles(Preferences.Instance.PhotoPath)
                .Where(file => Regex.IsMatch(file, @"^.+\.(gif|jpg|png)$"));
            int anz = imageFiles.Count();
            string randomPicture = imageFiles.ElementAt(new Random(DateTime.Now.Millisecond).Next(anz));

            using (var stream = File.Open(randomPicture, FileMode.Open))
            {
                Stream st = await stream.ReadAsync();
                var tweet = new SendTweetWithMediaOptions
                {
                    Status = Message,
                    Images = new Dictionary<string, Stream>
                        {
                            { "Gundel", st }
                        }
                };

                ts.SendTweetWithMedia(tweet, (t, r) =>
                 {
                     _status = r.StatusCode;
                 });
            }

            string logFilePath = Preferences.Instance.LogFilePath;
            if (!String.IsNullOrEmpty(logFilePath))
            {
                var logger = new Logger();
                logger.Log(_status, Message);
            }
        }

Aber das wirft einen Fehler, weil ReadAsync() Parameter erwartet.

Wie aber mache ich es richtig?

T
2.219 Beiträge seit 2008
vor 4 Jahren

Die Doku sagt doch dir welche Parameter du hingeben musst.
Da du Daten aus dem Stream lesen willst, musst du auch ein byte[] als Buffer übergeben, in dem die Daten abgelegt werden.
Die beiden int Werte sind einmal das offset im Stream und die Anzahl an Bytes die du lesen willst.
Erste wäre dann vermutlich 0 und zweite dann die Anzahl Bytes der Datei selbst.

Hier könntest du auch direkt über die File Klasse mit der ReadAllBytesAsync Methode arbeiten, die dann das selbe tut.
Dann brauchst du nur den Pfad sowie das CancelationToken.
Auch dazu solltest du mal in die Doku schauen.

Doku

Ansonsten solltest du deinen Code auch mal debuggen und keine wilden Vermutungen aufstellen.
Es bringt auch nichts, sich über den eigenen Code aufzuregen.
Hier solltest du gelassen und mit Bedacht an die Sache ran gehen.
Sonst drehst du dich ewig im Kreis und kommst nicht weiter.

Nachtrag:
Anbei kann dein Code nicht funktionieren.
Neben Parametern für ReadAsync liefert dir ReadAsync auch keinen Stream sondern einen Integer mit der Anzahl der gelesenen Bytes.
Wenn du, wie in einem Code, ein Dictionary <string, Stream> übergeben musst, dann musst du den FileStream, den dir File.Open liefert, als Stream in dem Dictionary speichern.

Und zusätzlich solltest du neben der Fehlermeldung auch immer den StackTrace prüfen.
Dieser bringt dich dem Problem vorallem beim debuggen fast schon zielgenau auf den Ursprung der Exception.
Nur in einigen Fällen kann es sein, dass dieser nicht stimmt oder gar fehlt.
Dies liegt dann meistens an der Release Version oder einem tieferliegenden Problem.
Das dürfte aber bei dir nicht der Fall sein, wenn du deinen Code debuggst.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 4 Jahren

Ich habe mal Dein anderes Thema gelöscht, da dort der Kontext fehlt und keiner alleine am Startpost eigentlich erkennen kann, was Sache ist.
Das neue Thema macht null sinn.

Um ehrliches Feedback zu geben: Dein Code ist totaler Murks
Hier werden quasi alle Empfehlungen missachtet und Du schmeisst alles in eine Methode rein, ohne auch nur ein bisschen auf Struktur oder Pattern zu achten.

Daher die wirklich wirklich eindringliche, wirklich positiv gemeinte Empfehlung: strukturier Dein Code.
Es sieht so aus, dass Du selbst total den Überblick verloren hast.

C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren

Wenn du, wie in einem Code, ein Dictionary <string, Stream> übergeben musst, dann musst du den FileStream, den dir File.Open liefert, als Stream in dem Dictionary speichern.

Aber das mache ich doch schon die ganze Zeit, nur dummerweise werfen die ReadTimeout und WriteTimeout Properties InvalidOperationExceptions und da bin ich mit meinem Latein am Ende, ist ja nicht so, dass ich keinen Debugger bedienen kann, und nicht schon zwei Stunden am Debuggen bin, und das Problem (ich hoffe, dass DAS hier das Problem ist ...) weiter eingekreist.

Das das Ganze nicht strukturiert ist, ist dagegen völliger Unsinn:

So ist die Preferences Klasse (hier nicht im Post) zum Beispiel als Singleton angelegt, damit die lesenden und setzenden Zugriffe nur einmal erfolgen müssen.

Die Send Methode benutzt das Strategy Pattern, da es zwei Send Klassen gibt, welche von ISend abgeleitet sind: eine für das Posten von einfachen Text Tweets (funktioniert übrigens) und eine die hier gepostete für das Posten von Bildern.

Die Auswahl der Strategy wird dabei von einer FactoryMethod übernommen, welche auf Basis der Setting die entsprechende Send Klasse wählt.

Und diese Aufrufe sind hinter einer Facade, so dass die Main Methode aus drei Zeilen besteht.

Vielleicht wird alles klarer, wenn ich das Projekt mal schildere:

Es geht um ein Forum, welches seinen Twitter Account gerne automatisch bespielen möchte.
Hierzu sollen in einer PHP Datei immer die aktuellen Themen gesondert ausgegeben werden.
Wir haben also konstanten Content.

Dieser TwitterBot soll dann als Chron Job einmal pro Stunde die festgelegte Url auf Twitter posten, wahlweise mit einem Bild, welches zufällig aus einem Ordner gewählt wird welchen man im config File angibt.
Hier gibt man auch die LogFile Datei an, bzw, die Message (die Url) und die ApKeys, die man für Twitter braucht.

Darum geht es.

16.806 Beiträge seit 2008
vor 4 Jahren

Und warum machst Du das nicht einfach sauber mit jeweils in ihren Verantwortlichkeiten getrennten Methoden bzw. auch sauber getrennten Services? 🤔
Das kann man alles schön asynchron simpel strukturieren. Ist keine Hexerei.

Hab stark den Eindruck, dass insgesamt bei Dir viel viel im Argen ist.
Angefangen beim Naming bis hin zur Struktur. Das ist nicht förderlichs fürs Verständnis.

C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren

HEUREKA!!! ES GEHT !!!

habe mir meine eigene von FileStream abgeleitete Custom Klasse geschrieben, die die Timeout Werte überschreibt:


class CustomFileStream : System.IO.FileStream
    {
        public override int ReadTimeout { get; set; }
        public override int WriteTimeout { get; set; }

        public CustomFileStream(string file, FileMode mode, int tr, int tw): base(file, mode)
        {
            ReadTimeout = tr;
            WriteTimeout = tw;
        }
    }

und dann


using (var stream = 
                new CustomFileStream(randomPicture, FileMode.Open,5000,5000))
            {
                var tweet = new SendTweetWithMediaOptions
                {
                    Status = Message,
                    Images = new Dictionary<string, Stream>
                        {
                            { "Gundel", stream }
                        }
                };

                ts.SendTweetWithMedia(tweet, (t, r) =>
                 {
                     _status = r.StatusCode;
                 });
            }

So, ich gehe mich jetzt besaufen !!! 😄 Das hab ich mir jetzt verdient.

16.806 Beiträge seit 2008
vor 4 Jahren

Hast jetzt nicht die Ursache, sondern die Symptome behandelt 😉

T
2.219 Beiträge seit 2008
vor 4 Jahren

Die Ursache kann man auch im Reference Code nachlesen.
FileStream hat keine eigene Implementierung für ReadTimeout/WriteTimeout.
Diese werden von Stream geerbt und dort wird die Exceptions sowohl im setter und getter für beide Timeouts ausgelöst.
Was genau versprichst du dir auch davon diese zu setzen?
Mal davon abgesehen, dass diese dann in deiner eigenen Implementierung keinen nutzen haben außer das du nun diese setzt?
Es gibt beim lesen/schreiben über FileStream auch keinen nutzen für ein Timeout.
Wenn du die Lese/Schreib Operationen abbrechen willst, nutzt die Async Variante und gib ein CancelationToken mit.
Damit kannst du die Operationen, falls nötig, abbrechen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren

Hast jetzt nicht die Ursache, sondern die Symptome behandelt 😉

Das Ding hat die ganze Zeit die Tweets versendet, trotz der Exceptions, es hat also FUNKTIONIERT.

Habe mir dann gedacht, OK, wenn nur die Exception das Problem ist, fängste sie einfach ab, und machst nen leeren catch Block, macht man zwar nicht, aber was soll ich machen, wenn der Fehler in der Fremd API liegt ???

Habe die Quellcodes (keine komplette VS Solution) auf github hochgeladen.

Gut möglich, dass ich beim strukturieren Fehler gemacht habe, oder man es zumindest optimaler hätte machen können, aber strukturiert programmiert habe ich ...

https://github.com/CoderboyPB/SimpleTwitterBot

C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren

Habe die Files jetzt mal die Quellcodes (keine komplette VS Solution) auf github hochgeladen.

Gut möglich, dass ich beim strukturieren Fehler gemacht habe, oder man es zumindest optimaler hätte machen können, aber strukturiert programmiert habe ich ...

https://github.com/CoderboyPB/SimpleTwitterBot

Sorry für Doppelpost, aber der geht auf die Forumssoftware ...

T
2.219 Beiträge seit 2008
vor 4 Jahren

Scheinbar hast du dir nicht mal die Mühe gemacht, die API zu prüfen.
Laut Code ist die Methode mit Obsolete markiert, da Twitter die Api auch jederzeit entfernen kann.

Link:
https://github.com/Yortw/tweetmoasharp/blob/master/src/TweetSharp/TwitterService.generated.cs


[Obsolete("Twitter has declared this method obsolete; it may cease to function at any time. Check https://dev.twitter.com/docs/api#deprecated for alternatives.")]
TwitterStatus SendTweetWithMedia(SendTweetWithMediaOptions options);

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren

ich hab die API über nuget installiert. Ne Doku hätte ich gern gehabt, aber keine gefunden

T
2.219 Beiträge seit 2008
vor 4 Jahren

Wenn du dir das NuGet Paket TweetSharp installiert hast, dann hast du auch die uralte Version von 2013.
Ich würde dir den Fork, von dem auch mein GitHub Link stammte, zu nehmen.
Dort wird dir dann auch eine entsprechende Meldung in VS angezeigt.

NuGet

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 4 Jahren

Hast jetzt nicht die Ursache, sondern die Symptome behandelt 😉

Das Ding hat die ganze Zeit die Tweets versendet, trotz der Exceptions, es hat also FUNKTIONIERT.

Aber nicht stabil - weil Du offensichtlich Probleme nur zudeckst statt sie im Code zu lösen.
Das versuchen wir Dir ja seit mehreren Beitragen klar zu machen.

C
CoderboyPB Themenstarter:in
327 Beiträge seit 2008
vor 4 Jahren

wenn es mein Code wäre, aber hier ist es eine FREMD Funktion, auf die ich, außer ihrem Aufruf, keinen Zugriff habe ...

T
2.219 Beiträge seit 2008
vor 4 Jahren

@CoderboyPB
Zwar mag dies stimmen, denoch hast du die Ursache des Problems nur umschifft.
Das Problem selbst löst du damit aber nicht.
Auch ist deine Lösung schon wegen der Obsoleten Api keine langfristige Lösung.
Kann sein, dass die API morgen schon von Twitter entfernt wird, dann funktioniert dein Bot überhaupt nicht mehr.

Bau deinen Code lieber jetzt auf eine saubere Lösung um, dann hast du später weniger Arbeit/Frust.
Du tust dir selbst damit einen gefallen, die aktuelle Lösung zu verwerfen und es gleich sauber zu machen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.