I'm scared of 'static'

wim sturkenboom

Well-known member
Joined
Aug 6, 2014
Messages
85
Location
Roodepoort, South Africa
Programming Experience
10+
I have the below class for sending emails asynchronously.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Net.Mail;
using System.ComponentModel;

namespace disney2sch
{
    class Mailer
    {
        public static bool sendEmailAsync(Configuration.EmailSetup esSetup, string strSubject, string strBody, List<string> lstRecipients, ref string errmsg)
        {
            MailMessage mm = new MailMessage();
            try
            {
                // setup mail message
                mm.IsBodyHtml = false;
                mm.From = new MailAddress(esSetup.mailfrom);
                if (!String.IsNullOrEmpty(esSetup.replyto))
                    mm.ReplyToList.Add(new MailAddress(esSetup.replyto));

                for (int cnt = 0; cnt < lstRecipients.Count; cnt++)
                {
                    mm.To.Add(lstRecipients[cnt]);
                }
                mm.Subject = strSubject;
                mm.Body = strBody;

                // send it
using (SmtpClientEx cl = new SmtpClientEx(esSetup.ServerOrIP, esSetup.port))
{
                    cl.LocalHostName = "localmachine";
                    if (!String.IsNullOrEmpty(esSetup.username))
                    {
                        cl.Credentials = new System.Net.NetworkCredential(esSetup.username, esSetup.password);
                    }

                    cl.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
                    cl.SendAsync(mm, "xx");
                }
            }
            catch (SmtpException ex)
            {
                errmsg = String.Format("Error sending mail");
                Logging.LogWriter lw = Logging.LogWriter.Instance;
                lw.WriteToLog(errmsg);
                lw.WriteToLog(String.Format("{0}", ex.Message));
                if (ex.InnerException != null && !String.IsNullOrEmpty(ex.InnerException.Message))
                {
                    lw.WriteToLog(String.Format("{0}", ex.InnerException.Message));
                }
                errmsg = ex.Message;
                return false;
            }
            catch (Exception ex)
            {
                errmsg = String.Format("Error sending mail");
                Logging.LogWriter lw = Logging.LogWriter.Instance;
                lw.WriteToLog(errmsg);
                lw.WriteToLog(String.Format("{0}", ex.Message));
                if (ex.InnerException != null && !String.IsNullOrEmpty(ex.InnerException.Message))
                {
                    lw.WriteToLog(String.Format("{0}", ex.InnerException.Message));
                }
                errmsg = ex.Message;
                return false;
            }
            finally
            {
                mm.Dispose();
            }

            return true;
        }

        private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
        {
            // Get the unique identifier for this asynchronous operation.
            String token = (string)e.UserState;
            string msg;
            Logging.LogWriter lw = Logging.LogWriter.Instance;

            if (e.Cancelled)
            {
                msg = String.Format("[{0}] Sending email canceled.", token);
                lw.WriteToLog(msg);
                return;

            }
            if (e.Error != null)
            {
                msg = String.Format("[{0}] Error sending email: {1}", token, e.Error.ToString());
                lw.WriteToLog(msg);
            }
            else
            {
                msg = String.Format("[{0}] Sending mail succeeded", token);
                lw.WriteToLog(msg);
            }
        }
    }
}

It does not work because disposing the client (as part of the using statement) cancels the sending. So I now basically need to dispose in the callback. But to be able to do so, the smtp client (cl) and probably the mail message (mm) need to be global. I'm happy to do so by adding the below two lines in the beginning of the class

private static MailMessage mm;
private static SmtpClientEx cl;


But I'm very worried about the implications if the sendMailAsync method is called a number of times in quick succession.
  1. Am I right in being worried? Or do I miss something about how it works?
  2. Is it possible to solve this using static methods? How?
  3. Or should I drop the idea of a static method and just instantiate a mailer class and use non-static methods?

Thanks for reading and advice.
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
3,141
Location
Sydney, Australia
Programming Experience
10+
It seems to me that you should probably not be using static methods and create an instance of your class. You can then have your class implement IDisposable and dispose those internal objects in your own Dispose method.
 

wim sturkenboom

Well-known member
Joined
Aug 6, 2014
Messages
85
Location
Roodepoort, South Africa
Programming Experience
10+
Thanks for the reply.

While waiting for replies, I tried a version where I instantiate and use non-static methods. It resulted in random errors about disposed objects :( Not relevant for now.
I've 'solved' the issue by using a different approach with a queue and a timer thread that flushes the queue on a regular interval and sends the emails synchronously.
 
Top Bottom