Announcement

Collapse
No announcement yet.

SendMail callback-problem

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • SendMail callback-problem

    Hallo,

    habe hier ein nur bedingt reproduzierbares Problem, will sagen es tritt nur sporadisch auf einem Server, aber leider nicht auf meiner Entwicklermaschine oder in meiner Testumgebung auf

    Im Eventlog findet sich ein Eintrag von .NET Runtime 2.0 Error Reporting
    clr20r3 [...] system.nullreferenceexception


    Folgender Ablauf:

    Mailversand mit SMTPClient.SendAsync(),

    Event SendCompleted triggert Fkt. SendCompletedCallback, diese ruft über statische Klasse Logging in Textdatei auf. Wenn der Fehler auftritt, schlägt das Logging fehl und der Dienst wird beendet:

    Code:
    private void SendCompletedCallback(....)
    { 
       try {
           string token = e.UserState;
       }
       catch [...]
       try {
           Logwriter.Log(token,"Some Text");
      }
      catch [...]
    
    }
    die Funktion Logwriter.Log sieht im Prinzip wie folgt aus:
    Code:
    void Log(string message1, string message2)
    {
       StreamWriter sw = null;
       try{
         using(sw=File.Append("c:\test.txt") {
             sw.WriteLine("{0},{1}"",message1,message2);
            sw.Dispose();
         }
       }
       catch [...]
    
    }
    Abgefangen wird der Fehler offenbar nicht durch die gesetzten Try..Catch Blöcke sonder erst von AppDomain.UnhandledException:

    Code:
    Unhandled Exception
    
    
    Object reference not set to an instance of an object.   at abc.Logwriter.Log(String caption, String message, String logfile)
       at abc.SendMail.SendCompletedCallback(Object sender, AsyncCompletedEventArgs e)
       at System.Net.Mail.SmtpClient.OnSendCompleted(AsyncCompletedEventArgs e)
       at System.Net.Mail.SmtpClient.SendCompletedWaitCallback(Object operationState)
       at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)-- inner Exception --

    Hat jemand eine Idee, was hier schiefläuft?
    Zuletzt editiert von b.IT; 09.04.2008, 15:48.

  • #2
    Hallo,

    Kann es sein, dass du keine Zugriffsberechtigung auf dein Logfile (hier C:\Test.txt) hast und diese System.IO - Exception nicht abfaengst?
    *-- robert.oh. --*

    Comment


    • #3
      Nicht wirklich - der Fehler tritt in ca. einem von 10 Fällen auf - also 9 mal wird die Logdatei ordentlich gefüllt - einmal schlägt es fehl...

      SendAsync() wird in allen Fällen mehrfach aufgerufen (ein Vorfall, 3 Nachrichten)

      Comment


      • #4
        a.) Beim Verlassen des Using Blocks wird Dispose von deinem Streamwriter automatisch aufgerufen (das ist der ja der eigentliche Sinn von using). Du rufst aber selber auch nochmal Dispose auf. Wahrscheinlich nicht problematisch aber zumindest unnötig.

        b.)Ich vermute dein Server macht selbstgestricktes multithreading(schließe ich aus der Erwähnung von Threadpool in deinem Stack). Du hast aber den Zugriff auf dein Log-file nicht synchronisiert. Das gibt Probleme beim parallelen Zugriff.
        Du solltest in deiner Log Methode mal einen Lock um den using Block setzen.

        ungefähr so (not tested)

        Code:
        private static object lockobject = new object();
        
        void Log(string message1, string message2)
        {
           lock(lockobject)
           {
               StreamWriter sw = null;
               try
               {
                 using(sw=File.Append("c:\test.txt") 
                 {
                     sw.WriteLine("{0},{1}"",message1,message2);
                    sw.Dispose();
                 }
               }
               catch [...]
            }
        }

        Comment


        • #5
          Danke für die Antwort,

          ich experimentiere gerade mit folgender Konstruktion

          Code:
          class Logwriter
          {
          
           static Semaphore sem = new Semaphore(2,2);
          
           void Log(string message)
           {
             sem.WaitOne();
          
             using(Textwriter tw = new Textwriter.Synchronize(File.Append("c:\\test.txt))){
              tw.WriteLine(message);
             }
          
          
             sem.Release();
          
          
          
           }
          
          }

          Comment


          • #6
            Code:
            static Semaphore sem = new Semaphore(2,2);
            Funktioniert das?
            Für mich heißt das maximal 2 Threads dürfen gleichzeitig den Code ausführen, der Semaphore Counter steht aber schon auf 2 sodas keiner im Moment an WaitOne() vorbeikommt. Oder ruftst du vorher noch irgendwo mal Release() auf?

            Du solltest auf jedenfall noch ein try .. finally um den Release() setzen. Wenn jetzt das Schreiben der Datei knallt wird Release nicht aufgerufen und kein Thread kommt mehr über WaitOne() hinaus. Bei einem lock kann dir das übrigens nicht passieren. Dort wird garantiert immer Monitor.Exit (lock arbeitet mit Monitoren) aufgerufen wenn der Block verlassen wird.

            Comment


            • #7
              Originally posted by Ralf Jansen View Post
              Code:
              static Semaphore sem = new Semaphore(2,2);
              Funktioniert das?
              nee

              aber das scheint zu wirken:

              Code:
              class Logwriter
              {
              
               static Semaphore sem = new Semaphore(1,1,"myGUID");
              private static TextWriter _file=null;
              
                 void Log(string message)
                 {
                    try
                    {
                           _file = new  Textwriter.Synchronize(File.Append("c:\\test.txt));
              
                           lock(_file)
                           {
                              sem.WaitOne();
                              using(_file)
                              {
                                  _file.WriteLine(message);
                               }
                            }
                    }
                    catch
                    {
                       //ERROHANDLING
                    }
                    finally
                    { 
                       sem.Release();
                    }
              }
              sem(1,1,"MyGuid") erzeugt eine systemweite Semaphore mit einem maximalen Thradcount von 1 und einem freien Thread (Semaphoren zählen rückwärts, eine Semaphore mit (0,x) ist voll belegt.


              (So viel Zeit für so wenig Code - gut das man nicht nach Zeilen bezahlt wird )
              Zuletzt editiert von b.IT; 13.04.2008, 23:50.

              Comment

              Working...
              X