This seems to be a pretty popular problem/question these days but I cannot seem to find a solution to the problem.
I have created a simple windows service in c# for sending out emails. The app works great except for it's memory usage. The front end of the app is web based and the service is queued by a text file being created in a directory. After reading the text file the service gathers the newsletter info and email addresses from MS SQL db and commences to send out 1 email every 4 seconds. While watching the service run through task manager, you can see the cpu usage bump up every 4 seconds but immediately drop back down. The memory on the other hand seems to bump up not every email but every 3-4 emails by 50-75k. This will continue to increment until all emails are sent. I just sent out approx. 2100 emails and the memory usage was up to 100MB. Another thing I have noticed is that after all emails are sent, the memory usage will hold at this total until I restart the service. When the service is idling, the memory runs at about 6500k. Anyone have any suggestions as to how I can get this memory usage down and disposed of after the mailings complete? My code is below. Any help would be greatly appreciated..
namespace NewsMailer
{
public partial class NewsMailer : ServiceBase
{
private FileSystemWatcher dirWatcher;
private static string filePath = @"E:\Intranets\Internal\Newsletter\EmailQueue";
private static string attachPath = @"E:\Intranets\Internal\Newsletter\Attachments";
private string newsType = String.Empty;
private string newsSubject = String.Empty;
private string newsContent = String.Empty;
private string userName = String.Empty;
private string newsAttachment = "";
private int newsID = 0;
private int emailSent = 0;
private int emailError = 0;
public NewsMailer()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
dirWatcher = new FileSystemWatcher();
dirWatcher.Path = filePath;
dirWatcher.Created += new FileSystemEventHandler(ReadText);
dirWatcher.EnableRaisingEvents = true;
}
protected override void OnStop()
{
dirWatcher.EnableRaisingEvents = false;
dirWatcher.Dispose();
}
private void ClearVar()
{
newsType = String.Empty;
newsSubject = String.Empty;
newsContent = String.Empty;
userName = String.Empty;
newsAttachment = "";
newsID = 0;
emailSent = 0;
emailError = 0;
}
private void ReadText(object sender, FileSystemEventArgs e)
{
ClearVar();
SetLimits();
string txtFile = filePath + @"\QueueEmail.txt";
StreamReader sr = new StreamReader(txtFile);
string txtLine = String.Empty;
try
{
while ((txtLine = sr.ReadLine()) != null)
{
string[] lineCpl = txtLine.Split('§');
newsType = lineCpl[0];
userName = lineCpl[1];
newsID = Convert.ToInt32(lineCpl[2]);
}
}
catch (IOException ex)
{
SendExByMail("ReadText() IO Error", ex);
}
catch (Exception ex)
{
SendExByMail("ReadText() General Error", ex);
}
finally
{
sr.Close();
sr.Dispose();
}
GetNews();
}
[DllImport("kernel32.dll")]
public static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);
private void SetLimits()
{
GC.Collect();
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
}
private void DeleteText()
{
try
{
File.Delete(filePath + @"\QueueEmail.txt");
}
catch (IOException ex)
{
SendExByMail("DeleteText() IO Error", ex);
}
catch (Exception ex)
{
SendExByMail("DeleteText() General Error", ex);
}
}
private void GetNews()
{
string connectionString = ConfigurationManager.ConnectionStrings["contacts"].ConnectionString;
SqlConnection conn = new SqlConnection(connectionString);
string sqlSELECT = "SELECT newsSubject, newsContents, username, attachment FROM newsArchive " +
"WHERE ID = " + newsID;
SqlCommand comm = new SqlCommand(sqlSELECT, conn);
try
{
conn.Open();
using (SqlDataReader reader = comm.ExecuteReader())
{
while (reader.Read())
{
newsSubject = reader[0].ToString();
newsContent = reader[1].ToString();
userName = reader[2].ToString();
newsAttachment = reader[3].ToString();
}
reader.Dispose();
}
}
catch (SqlException ex)
{
SendExByMail("GetNews() SQL Error", ex);
}
catch (Exception ex)
{
SendExByMail("GetNews() General Error", ex);
}
finally
{
comm.Dispose();
conn.Dispose();
}
DeleteText();
GetAddress();
}
private void GetAddress()
{
string connectionString = ConfigurationManager.ConnectionStrings["contacts"].ConnectionString;
SqlConnection conn = new SqlConnection(connectionString);
string sqlSELECT = String.Empty;
if (newsType == "custom")
sqlSELECT = "SELECT DISTINCT email FROM custom";
else
sqlSELECT = "SELECT DISTINCT email FROM contactsMain WHERE queued = 'True'";
SqlCommand comm = new SqlCommand(sqlSELECT, conn);
try
{
conn.Open();
using (SqlDataReader reader = comm.ExecuteReader())
{
while (reader.Read())
{
try
{
if (CheckEmail(reader[0].ToString()) == true)
{
SendNews(reader[0].ToString());
Thread.Sleep(4000);
emailSent++;
}
else
{
SendInvalid(reader[0].ToString());
emailError++;
}
}
catch (SmtpException ex)
{
SendExByMail("NewsLetter Smtp Error", reader[0].ToString(), ex);
emailError++;
}
catch (Exception ex)
{
SendExByMail("Send NewsLetter General Error", reader[0].ToString(), ex);
emailError++;
}
finally
{
UnqueueEmail(reader[0].ToString());
}
}
reader.Dispose();
}
}
catch (SqlException ex)
{
SendExByMail("GetAddress() SQL Error", ex);
}
catch (Exception ex)
{
SendExByMail("GetAddress() General Error", ex);
}
finally
{
comm.Dispose();
conn.Dispose();
}
SendConfirmation();
}
private bool CheckEmail(string emailAddy)
{
bool returnValue = false;
string regExpress = @"^[\w-]+(?:\.[\w-]+)*@(?:[\w-]+\.)+[a-zA-Z]{2,7}$";
Match verifyE = Regex.Match(emailAddy, regExpress);
if (verifyE.Success)
returnValue = true;
return returnValue;
}
private void SendNews(string emailAddy)
{
string today = DateTime.Today.ToString("MMMM d, yyyy");
using (MailMessage message = new MailMessage())
{
SmtpClient smtpClient = new SmtpClient();
MailAddress fromAddress = new MailAddress("");
message.From = fromAddress;
message.To.Add(emailAddy);
message.Subject = newsSubject;
if (newsAttachment != "")
{
Attachment wusaAttach = new Attachment(attachPath + newsAttachment);
message.Attachments.Add(wusaAttach);
}
message.IsBodyHtml = true;
#region Message Body
message.Body = "";
#endregion
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
smtpClient.Host = "";
smtpClient.Credentials = new System.Net.NetworkCredential("");
smtpClient.Send(message);
smtpClient.ServicePoint.CloseConnectionGroup(smtpClient.ServicePoint.ConnectionName);
}
}
private void UnqueueEmail(string emailAddy)
{
string connectionString = ConfigurationManager.ConnectionStrings["contacts"].ConnectionString;
SqlConnection conn = new SqlConnection(connectionString);
string sqlStatement = String.Empty;
if (newsType == "custom")
sqlStatement = "UPDATE custom SET queued = 'False' WHERE email LIKE '" + emailAddy + "'";
else
sqlStatement = "UPDATE contactsMain SET queued = 'False' WHERE email LIKE '" + emailAddy + "'";
SqlCommand comm = new SqlCommand(sqlStatement, conn);
try
{
conn.Open();
comm.ExecuteNonQuery();
}
catch (SqlException ex)
{
SendExByMail("UnqueueEmail() SQL Error", ex);
}
catch (Exception ex)
{
SendExByMail("UnqueueEmail() General Error", ex);
}
finally
{
comm.Dispose();
conn.Dispose();
}
}
private void SendConfirmation()
{
SmtpClient smtpClient = new SmtpClient();
using (MailMessage message = new MailMessage())
{
MailAddress fromAddress = new MailAddress("");
MailAddress toAddress = new MailAddress();
message.From = fromAddress;
message.To.Add(toAddress);
//message.CC.Add(ccAddress);
message.Subject = "Your Newsletter Mailing Has Completed";
message.IsBodyHtml = true;
message.Body = "Total Emails Sent: " + emailSent +
"<br />Total Email Errors: " + emailError +
"<br />Contact regarding email errors if any were found";
smtpClient.Host = "";
smtpClient.Credentials = new System.Net.NetworkCredential("");
smtpClient.Send(message);
smtpClient.ServicePoint.CloseConnectionGroup(smtpClient.ServicePoint.ConnectionName);
}
ClearVar();
System.GC.Collect();
}
private void SendInvalid(string emailAddy)
{
SmtpClient smtpClient = new SmtpClient();
using (MailMessage message = new MailMessage())
{
MailAddress fromAddress = new MailAddress("");
MailAddress toAddress = new MailAddress("");
message.From = fromAddress;
message.To.Add(toAddress);
//message.CC.Add(ccAddress);
message.Subject = "Invalid Email Address";
message.IsBodyHtml = true;
message.Body = "An invalid email address has been found, please check the following " +
"email address:<br />" + emailAddy;
smtpClient.Host = "";
smtpClient.Credentials = new System.Net.NetworkCredential("");
smtpClient.Send(message);
smtpClient.ServicePoint.CloseConnectionGroup(smtpClient.ServicePoint.ConnectionName);
}
}
private void SendExByMail(string subject, Exception ex)
{
SmtpClient smtpClient = new SmtpClient();
using (MailMessage message = new MailMessage())
{
MailAddress fromAddress = new MailAddress("");
MailAddress toAddress = new MailAddress("");
message.From = fromAddress;
message.To.Add(toAddress);
//message.CC.Add(ccAddress);
message.Subject = subject;
message.IsBodyHtml = true;
message.Body = "An Error Has Occurred: <br />Exception: <br />" + ex.ToString();
smtpClient.Host = "";
smtpClient.Credentials = new System.Net.NetworkCredential("");
smtpClient.Send(message);
smtpClient.ServicePoint.CloseConnectionGroup(smtpClient.ServicePoint.ConnectionName);
}
}
private void SendExByMail(string subject, string body, Exception ex)
{
SmtpClient smtpClient = new SmtpClient();
using (MailMessage message = new MailMessage())
{
MailAddress fromAddress = new MailAddress("", "MailerService");
MailAddress toAddress = new MailAddress("");
message.From = fromAddress;
message.To.Add(toAddress);
//message.CC.Add(ccAddress);
message.Subject = subject;
message.IsBodyHtml = true;
message.Body = "An Error Has Occurred:<br /><br />" + body + "<br /><br />Exception: <br />" + ex.ToString();
smtpClient.Host = "";
smtpClient.Credentials = new System.Net.NetworkCredential("");
smtpClient.Send(message);
smtpClient.ServicePoint.CloseConnectionGroup(smtpClient.ServicePoint.ConnectionName);
}
}
}
}