Introduction
“Necessity is the mother of invention”… so the true…idea of this application comes to my mind in the class for “application development foundation” while studying the file system watcher. We had a problem with the college online blackboard and one of my friends was not able to access the online blackboard and hence he was not able to download the lectures and presentations from there. So we always had to email the presentation to him in every lecture, so this idea of an automated mailing system came to my mind.
Creating the Watcher
So, the first step is to create a file system watcher. We are going to use FileSystemWatcher
class for this and this listens to the file system change notifications and raises events when a directory, or file in a directory changes. A word of caution: By default, the buffer is set to a size of 4 KB. A 4 KB buffer can track changes on approximately 80 files in a directory. Each event takes up 16 bytes in the buffer, plus enough bytes to store the name of the file, in Unicode (2 bytes per character), that the event occurred on.
The main properties that we are going to use here are IncludeSubdirectories
, NotifyFilter
and the event Created
. You can use different events depending on the requirement. Here is the list of all the events from the FileSystemWatcher
class.
Changed
: Occurs when a file or directory in the specified Path is changed.Created
: Occurs when a file or directory in the specified Path is created.Deleted
: Occurs when a file or directory in the specified Path is deleted.Disposed
: Occurs when the component is disposed by a call to the Dispose
method.Error
: Occurs when the internal buffer overflows.Renamed
: Occurs when a file or directory in the specified Path is renamed.
FileSystemWatcher fsw = new FileSystemWatcher(@"Directory Path");
fsw.IncludeSubdirectories = true;
fsw.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite;
fsw.Created += new FileSystemEventHandler(fsw_Changed);
The Windows operating system notifies your component of file changes in a buffer created by the FileSystemWatcher
. If there are many changes in a short time, the buffer can overflow. This causes the component to lose track of changes in the directory, and it will only provide blanket notification. Increasing the size of the buffer with the Internal Buffer Size property is expensive; as it comes from non-paged memory that cannot be swapped out to disk, so keep the buffer as small yet large enough to not miss any file change events. To avoid a buffer overflow, use the NotifyFilter
and IncludeSubdirectories
properties so you can filter out unwanted change notifications.
You have to set the EnableRaisingEvents
to true
to start monitoring the events.
fsw.EnableRaisingEvents = true;
Console.WriteLine("Press a key to end the program.");
Console.ReadKey();
Sending the Email
For email, you have to use the System.Net.Mail
namespace. The System.Net.Mail
namespace contains classes used to send electronic mail to a Simple Mail Transfer Protocol (SMTP) server for delivery.
The MailMessage
class represents the content of a mail message. The SmtpClient
class transmits email to the SMTP host that you designate for mail delivery. You can create mail attachments using the Attachment
class.
Creating the SMTP client….
The SmtpClient
class is used to send e-mails to an SMTP server for delivery. Port 587 is for users to send out emails on. Here is how to create the smtpclient
object.
var fromAddress = new MailAddress("email address", "Name of the Sender");
var toAddress = new MailAddress("email address", "Receiver Name");
const string fromPassword = "password";
const string subject = "subject";
const string body = "body of the email";
var smtp = new SmtpClient
{ Host = "smtp.gmail.com", Port = 587, EnableSsl = true,DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false, Credentials = new NetworkCredential(fromAddress.Address, fromPassword)};
Creating the Attachment
I have just created a filestream
and have provided this to the constructor of attachment. Attachment content can be a String
, Stream
, or filename.
FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
Attachment data = new Attachment(fileStream,"Name");
Creating the Mail Message
Finally, we come to creating the email message. The sender, recipient, subject, and body of an e-mail message may be specified as parameters when a MailMessage
is used to initialize a MailMessage
object. These parameters may also be set or accessed using properties on the MailMessage
object.
After assembling your e-mail message, you can send it by using the end
method.
using (var message = new MailMessage(fromAddress, toAddress)
{ Subject = subject, Body = body })
{
message.Attachments.Add(data);
try
{
smtp.Send(message);
}
catch (Exception ex)
{
Console.WriteLine("Exception caught in CreateMessageWithAttachment(): {0}", ex.ToString());
}
}
Now We Have a Problem
While running this application, I came across the problem with larger attachments. In slower networks, it may take a long time to attach the files so I tried to use asynchronous programming here. I tried to start the second thread in the event of the filesystemwatcher
class like this:
private static void fsw_Changed(object source, FileSystemEventArgs e)
{
Program p = new Program();
DoWorkDelegate del = new DoWorkDelegate(p.DoWork);
IAsyncResult ar = del.BeginInvoke(e.FullPath,new AsyncCallback(p.DoWorkCallback), del);
}
You can put all the code that is time consuming in the dowork
method.
And you can use AsyncCallback
to give a confirmation of the attachment attached or mail sent.
public void DoWorkCallback(IAsyncResult res)
{
Console.WriteLine("Message sent");
DoWorkDelegate del = res.AsyncState as DoWorkDelegate;
del.EndInvoke(res);
}
Further Development and References
You can play around with the filesystemwatcher
and use it to create a lot of cool applications. You can use it to log the application installation details and to monitor the changes in a particular directory.
Thanks.