Creating a Dynamic Email Drop Box Series
Part 1 The author discusses the creation of an email drop box that would allow a site’s users to accept data into their profiles via email sent to accounts that didn’t physically exist.
Part 2 In this article we will take a look at the first half of our task list.
Part 3 In this article we’re going to build the drop box application.
Introduction
In the last article we took a look at setting up the base framework for our dynamic email drop box application. We configured our pop3 server to accept email on behalf of our users. We then created a pop3 client framework to allow our application to communicate with our pop3 server. Then we analyzed the incoming email packets and set up some basic email parsing to make working with the received emails a little less painful. With the PopClient completed we created a quick little test harness to make sure that it works as expected.
With this base framework laid out for us we can now start to look at the meat and potatoes of the drop box application. In this article we will tackle more refined parsing. We will then look to matching our email sender and receivers to accounts in our application. And we will look at extending the email itself in a way that we can support more specific features such as status updates, blog posts, and general messaging. Once we have our drop box application working we will need to wrap a test harness around it and see things in action. And finally, once the application is proven to work we will create a drop box monitor in the form of a windows service so that the application can run without supervision.
Let’s get started!
Building the drop box application
In this section we will take a look at building up the actual drop box application. This implementation will stay fairly generic throughout but will give you all the tools you need to build up from here depending on what type of feature you wish to support. We will have to develop a small database to house our accounts, status updates, blog posts, and messages to illustrate the parsing of various formats into those sorts of features. We will also create some additional parsers to help us work in more detail with our email messages.
Near the end of this section we should be able to clearly identify a method or a group of methods in our application or the PopClient application that can perform the following steps.
- Connect to our pop3 server using our
PopClient.
- Get a list of messages off of our pop3 servers queue.
- Parse the list messages into a list of drop box messages.
- Identify the accounts of the senders and receivers of each message.
- Save all of those drop box messages to the database.
- Delete the messages from the pop3 server.
- Close the connection to the pop3 server.
Once we can identify the path in our code that addresses each of these points we can then start to assemble each point into a working application!
Creating the drop box project
As with most new projects the best place to start is by adding a new project to our existing solution (which we developed in our last article). We will be adding another class library project to our solution. I named mine DropBox and saved it to our trunk/src directory. I updated my assembly and namespace to be AndrewSiemer.DropBox as well. Once this was done I then added references to the various libraries that we will need for this application. In this case I referenced our PopClient application (which we developed in the last article) and a reference to System.Configuration (to read our configuration file). I then added an existing item and pointed a reference to the app.config file that we placed in our src directory while working in our last article.
With the basic project set up complete I then added some folders. I added a Domain folder to hold our LINQ to SQL dbml file as well as some other domain objects that we will discuss later. I then added a DataAccess folder to hold all of the repository classes that we will create. And I added a Services folder to hold our application services. Inside the Services folder I added a Parsers folder to specifically hold the service classes that deal with parsing.
Creating the database
With our new project created we can briefly turn our attention to creating our simple database. You may be wondering why this is the next step. Since I plan to use LINQ to SQL to connect too and interact with our database it is the logical next step. LINQ to SQL will generate our domain objects from the tables that we pull in from our database. Let’s create the database and then we can dig more into the LINQ to SQL aspect.
To get started I am going to create a new SQL Server database using the SQL Server Management Studio. I named this database DynamicEmailDropBox. I then changed the location of where to create the database files and placed them under my trunk directory in a db directory to keep everything related to this project in one location. My very next step is to create a new SQL Server login. I named the login DynamicEmailDropBox_dev and associated it with my DynamicEmailDropBox database. I then put my new account into the db_owner role for our database (giving it full access to do just about anything).
Note: Don’t use db_owner in production! If you use this in a production environment make sure that you revisit the security configuration of this account!
Now that we have a new database created and configured so that our application can get to it lets make our first table. The first table we will create is the Accounts table. This table will have an AccountID field that is an auto incrementing primary key for us to help us associate other items back to this account. It will also store the username and email address for each account. The username and email address will be used when we create our account matching facilities. We will use the “from” email address in an email to match to our Accounts.Email field and we will use the first part of the “to” email addresses to match to our Accounts.Username field.
Listing 1: SQL for the Accounts table
Next we will create the Messages table. This table will hold the content of emails that we receive that are either not tagged according to our supported tags or that are not tagged at all. This will be our catch all bucket for email that is not parsed appropriately or is sent as a message from one user to another. This table will have the following fields: MessageID, AccountID, Subject, Body, and CreateDate. MessageID will be an auto incrementing int and act as the primary key for this table. AccountID will store who owns the record. Subject, Body, and CreateDate will hold corresponding data to the parsed email.
Listing 2: SQL for the Messages table
Next we will create a Posts table which will hold the data for emails that are sent with the “post” tag. This table will be made up of the following fields: PostID, AccountID, Subject, Body, and CreateDate. Were this a real application that support blog posts there would obviously be many other blog related data points! In this case we use the PostID as the auto incrementing primary key of this table and AccountID for ownership identification. Like Messages, the other fields map to the email parts.
Listing 3: SQL for the Posts table
Finally we will have a StatusUpdates table that will hold Twitter like status updates. This table will be made up of the following fields: StatusID, AccountID, Status, and CreateDate. StatusID will be the auto incrementing primary key and AccountID maps to our Accounts table. The Status field will be filled with the subject of emails tagged as “status”. CreateDate will capture the date that the status email was sent.
Listing 4: SQL for the StatusUpdate table
LINQ to SQL
With the database defined and ready for our application to connect too we can now return to our DropBox project. Navigate to the Domain directory that we created earlier and add a new item. We are going to add a LINQ to SQL Classes item which will take care of connecting to our database, generating classes based on our tables, and handling all the database interactions. Name this item DropBox.dbml.
Note: Why is the .dbml name important? Know that whatever you name your .dbml file will impact your coding efforts down the road. The code generator from the LINQ to SQL wizard will create a DataContext for you that is named {FileName}DataContext. If you named your .dbml DropBox as defined above you will end up with a DropBoxDataContext. If you named it DynamicEmailDropBox then you will end up with a DynamicEmailDropBoxDataContext. This can obviously get a bit wordy!
Once the .dbml file is saved to the project you will see the LINQ to SQL design surface open up. This is where we will drag the tables and other database objects that we want to work with in our project. The next step is to set up a connection to our new database.
To set up a connection open up your server explorer window. You will see a Data Connection node. From there right click and add a new connection. In the “Server name” section enter the name of your database server (the computer name of your local computer) and the instance name of your database server if there is one. I am using SQL Express on my lap top so I used dev1\sqlexpress. Then select “Use SQL Server Authentication” and enter your username and password from when we created the SQL Login before. Now you can choose the data base in the “Select or enter a database name” drop down. Your configuration should look roughly like below.

From there you can navigate into your solution explorer and expand the Tables node. Your solution explorer should look roughly like this.

From here you can now drag all four of your tables on to the LINQ to SQL design surface. This should look roughly like the image below.

Note: Why are my entities not related to one another? For those of you that have used LINQ to SQL before you may be wondering why none of the entities that we just created are related to one another. We never defined a relationship between the objects at the database level so they were not created here. Had we created the relationships in the database though, and they showed up here, I would have deleted them anyways! It makes life much easier to work with un-related entities in LINQ to SQL.
With our database and project configurations and synchronization complete you may want to take a quick second to build your project. This will create the four entity classes for us under the “Domain” namespace and prove that things are working as expected.
Creating the repository layer
Now that we have a database and our four basic domain objects created we can start to think about other things. The next easiest item to do is to create our repository layer. The repository layer is generally an easy layer to get going as it is responsible for our database interactions and usually has very distinct functionality. In this case it will only be responsible for a couple of queries and a few insert methods.
Before we get to writing queries though we need to create a quick abstraction with regards to connecting to our underlying database from within the confines of our DataContext. To do this we will add a Connection class to our DataAccess folder. This class will have one method, GetContext. The GetContext method will be responsible for getting a DropBoxDataContext running for the objects in our repository layer.
But before we look at the Connection class we will need to build out a dependency first. We will need to create a ConfigurationService class that can get a connection string from our shared app.config.
Listing 5: Services.ConfigurationService.cs – ConfigurationService
Then we need to add our connection string to our shared app.config file.
Listing 6: trunk/src/app.config
Note: Beware of Settings.settings configuration behind the scenes! Just an FYI but when you created your connection and dragged tables to the design surface Visual Studio took it upon itself to store your connection settings in the Properties/Settings.settings file and then mapped that configuration into your Domain/DropBox.designer.cs file. This means that your connection string is stored in your app.config file (which you can change as you like) and stored in a compiled resource which your application will use (which can’t be changed on the fly). I strongly urge you to delete this settings configuration and update your designer file to use your new ConfigurationService.GetDropBoxConnectionString method! After deleting the settings value navigate to your DropBox.designer.cs file and look for the DropBoxDataContext method. You will notice that it passes to its base constructor the settings configuration. Swap this out for a call to your configuration service method. You may have to check that this sticks from time to time as this code is generated for you!
With the ConfigurationService class in place we can now look at our Connection class.
Listing 7: DataAccess.Connection.cs – Connection
As you can see in the listing above we created a _connectionString variable and loaded it from our ConfigurationService.GetDropBoxConnectionString method. We then passed _connectionString into the constructor of our LINQ to SQL generated DropBoxDataContext and returned that new instance out to our caller. That’s it!
Now we can take a look at an AccountRepository. We will start by adding a new class to our DataAccess folder. Call it AccountRepository. The AccountRepository will have only two methods, GetAccountIDsByEmails and GetAccountIDsByUsernames. These methods are 99% identical with the exception of a few small changes so I will show one and explain it and you can look at the other one in the source code download.
Lets take a look at the GetAccountIDsByEmails method. This method accepts a list of email addresses in the form of a generic List of strings and returns a Dictionary with a string key and an int value. The idea here is that when parsing a batch of emails we will need to be able to turn a handful of email addresses into their appropriate Account.AccountIDs so that we can build records such as Post, StatusUpdate, and Message.
To do this we will take the list of email addresses and through a LINQ query look for all the records where our emails contain the Account.Email. Then we will select out only the AccountID and Email which is needed for our dictionary response as the key/value pair. Since we want to transform the result of this query into a dictionary we have to be sure that the key’s are unique so we will immediately call Distinct on our query result. Then we can transform the IEnumerable result set to a dictionary with the ToDictionary call where we specify the email as the key and the accountID as the value. We then return the result to the caller.
Note: Make sure to dispose of the DataContext appropriately! I wanted to point out that I am retrieving a DropBoxDataContext from my Connection class in a using statement. This means that when the scope of the using statement is complete that my DropBoxDataContext and Connection object will be disposed of appropriately. This is very important to remember. If you create an instance of Connection and an instance of the DropBoxDataContext and don’t dispose of them you may be inadvertently leaving a connection to your database open. This can result in all sorts of performance related issues! Remember to use a connection quickly and then get rid of it as fast as possible.
Listing 8: DataAccess.AccountRepository.cs – AccountRepository.GetAccountIDsByEmails
From here we can discuss all three of our other repository classes. We will need to create a MessageRepository, PostRepository, and StatusUpdateRepository. All of these repositories will be identical with the exception of what they are working with. Each repository will have a Save{objectName} method that will take a list of objects and save them into the appropriate table. For that reason I will cover one of these repository classes and let you look at the source for the other two.
The PostRepository is responsible for taking a generic List of Post objects and saving them to the database for us. This will be used by our application when we start to parse emails that have the tag “post” in them. We will build up a list of Post objects as we process all of our drop box emails and once complete, save this list of Posts to the database via this method. This method is similar to the AccountRepository in its use of the using statement. From there we have two lines of code. One that invokes the InsertAllOnSubmit method off of the DataContext and another that calls SubmitChanges.
Listing 9: DataAccess.PostRepository.cs – PostRepository
Each of the other repository classes is identical to the above code except that they handle a different set of objects to save to the database.
Note: Why don’t you use a generic Save method? Those of you familiar with LINQ to SQL and the many various frameworks out there might be aware that there is a generic way to write a single save method at a higher level in the code. This method would take a list of items and interrogate their type to determine which table to save them too. This will reduce the number of lines of code you have to write as it handles each of your databases tables. I didn’t feel that for this example this was quite appropriate. Also, I generally don’t use this generic concept as I like to maintain a bit more control on a per table basis. For those that are interested:
http://kianryan.livejournal.com/33081.html
http://www.codeproject.com/KB/linq/LinqAndUnity2.aspx
Extending our domain
Now that we have our database, the entities generated from the database, and some basic methods to communicate with our database, let’s think a bit more about our application to see if we are missing any other core components before we start to “hook things up”. If I were to describe what our application does in one line it would be this:
“Our application will connect to a specified email address, pull down any queued email messages, parse those messages to identify blog posts, messages, and status updates by a known Tag as well as identify who sent them and who is to receive them, and then store each of those communication types to the appropriate location in our database.”
Given this statement above we know that we need to be able to connect to our email server which we handled by creating our PopClient (in the last article). We need to be able to download and parse any emails that are queued (also a function of PopClient). We then need to parse out the type of message each email is as well as who sent the message and who is to receive the message. And then we need to store each of those messages in the appropriate location.
From this I see that we will need at least two more additional domain objects. I am thinking that we will need a DropBoxMessage to hold the email message as well as the tag type, who sent it, and who is to receive it. And from that statement we have identified a second object that we will need in the form of a tag type, or more specifically a TagType.
The TagTypes object will be an enum which will hold the specific tags that we will support and will be placed in the Domain folder. (add a new class to the domain folder and change it from class to enum) This will give us a strongly named way to communicate what type of tag an email message has in it. In this application we will support BlogPost, StatusUpdate, and an untagged message which we will tag as a Message.
Listing 10: Domain.TagTypes.cs – TagTypes
The DropBoxMessage will be a class that is also added to our Domain folder. It will have all the fields of a PopClient Message but will also have the added properties of the Tag, FromAccountID, and ToAccountID.
Listing 11: Domain.DropBoxMessage.cs – DropBoxMessage
With our data access layer completed and our domain layer moved far enough along to get started we can now take the next step and start to discuss the various forms of parsing that we need to perform.
Creating more parsers
You may have already guessed it but the majority of this application is about parsing blobs of text and then doing something with what we find (honestly we are barely scraping the surface with parsing here in that our email messages have a wealth of information in them that you could use for your application). We already have the raw email parsing being done by the PopClient and don’t need to look at that further. However, we need to extend the PopClient.Message that is returned by that parser by performing some drop box specific parsing to identify who sent the message (EmailAddressParser), who is to receive the message (UsernameParser), and whether that message is tagged or not (TagParser).
The EmailAddressParser will use a Regex pattern match to extract an email address (or all email addresses) from the passed in string. It will have three methods, one to parse a single address (the first one found), one to parse all email addresses, and a private method that actually does the parsing for both of the other methods. I will show the worker method as the other two methods are self explanatory.
Listing 12: Services.Parsers.EmailAddressParser.cs – EmailAddressParser
As you can see from the listing above the work that is being done here is by way of this regex pattern:
It says something to the effect (as I am not a regex expert) that we are looking for a word, possibly with a dot and another word, a @ sign, possibly a period with another word, followed by a word, a period, and a word. This is by no means the best pattern to account for all emails but it works for this article!
We get a list of matches by way of this Regex and then iterate through them adding each match to our resulting list of email addresses which is then returned to one of the two calling methods.
Note: Code update from the second article. I found an issue with the PopClient.ParseMessage method discussed in the second article in that it didn’t always perform as expected. In some cases the rudimentary parsing worked great…in other cases it didn’t work at all. So I took the EmailAddressParser that we just created and plugged it in to the section of the PopClient that parses the “from” section of the email message that is being parsed. I added a new EmailParser.cs file to the PopClient project and duplicated the EmailAddressParser contents from the DropBox project into that file. I am treating these two projects as separate tool sets and want as few dependancies created as possible! You could just as easily use the EmailAddressParser from the PopClient project in the DropBox project if you like.
Next we can discuss the much easier UsernameParser. Its job is to extract the username from an email address. We need this because people will be sending emails to our system for email addresses that don’t exist. What will exist is the username in the front of the email address. This is the dynamic part of our email drop box application. We will extract this username (and then later) match it to an Account in our system.
This parser will use the EmailAddressParser to extract an email address from the passed in string (just in case it is not already an email address!). From there we Split the email address on the @ sign (where there can only be one of). And then we make sure that we have two items in our Split result (the username and the domain) and assign the first item to our result which is then returned to the caller (the username).
Listing 13: Services.Parsers.UsernameParser.cs – UsernameParser
Our final parser is the TagParser. This parser initially had only one job, to determine which tag an email had assigned to it if it indeed had one at all. During message transformation (coming up soon) I also found that we needed the ability to parse the tag out of the message all together to clean up the message. So this removal parser is included too! (otherwise we would see a status in our database that said “status – here is my status message” instead of the more appropriate “here is my status message”)
The first part of the TagParser is the TagParser.Parse method. This method identifies the tag in the subject of an email message. This is done by checking if the subject StartsWith the allowed tag name. If it finds a tag name in the subject then the appropriate Tag from the TagTypes enum is returned. If no Tag is found then the TagTypes.Message Tag is returned. All emails are tagged in our system!
Listing 14: Services.Parsers.TagParser.cs – TagParser.Parse
In the TagParser.RemoveTag method we are performing similar functionality to identify what type of tag is in the passed in text but in this case we are attempting to clean out all remnants of that tag. The cleaned result is then passed out (self explanatory).
Listing 15: Services.Parsers.TagParser.cs – TagParser.RemoveTag
Now that we have our parsers completed we can get to the guts of the application and start tying all of the pieces together! Lets get our drop box application running.
Drop box processing
All of the logic of our application is now safely created in the various helper classes and external frameworks so it is now time to sew everything together. At this point most of our code is created. We may need a few more services to link some concepts together though! Let’s see if we can identify them from our earlier list of tasks that we need to be able to perform.
- Connect to our pop3 server using our
PopClient.
- Get a list of messages off of our pop3 servers queue.
- Parse the list messages into a list of drop box messages.
- Identify the accounts of the senders and receivers of each message.
- Save all of those drop box messages to the database.
- Delete the messages from the pop3 server.
- Close the connection to the pop3 server.
If you think about each of the points above you should now be able to clearly visualize a path in our code base to achieve each task. Let’s identify them.
Table 1: Tasks and methods used to accomplish them
Task | Method |
Connect to our pop3 server using our PopClient | PopClient.Connect(); |
Get a list of messages off of our pop3 server queue | PopClient.GetMessages(); |
Parse the list of messages into a list of drop box messages | *We need a service here to transform a Message into a DropBoxMessage |
Identify the accounts of the senders and receivers of each message | *We need a service here to get our Account specific information |
Save all of those drop box messages to the database | *We need to get our drop box messages to the database |
Delete the messages from the pop3 server | PopClient.DeleteMessages(); |
Close the connection to the pop3 server | PopClient.Disconnect(); |
From the list above I see that we need the following “service” style classes:
MessageTransformer: to convert from Message to DropBoxMessage
AccountMatchingService: to locate the Account related information for a message
MessageService: to do some work prior to saving to our MessageRepository
PostService: to do some work prior to saving to our PostRepository
StatusUpdateService: to do some work prior to saving to our StatusUpdateRepository
Let’s get to it!
We will address these service classes in the order that they are needed starting with the MessageTransformer. This class is responsible for taking in a list of messages with possibly multiple recipients and turning them into a list of drop box messages with only one recipient. For the most part this is a direct mapping of properties such as Message.From to DropBoxMessage.From. In other cases we will need to map items while iterating through the array of receiving email addresses. And in some other cases we need to further parse the Message down as is the case for determining the DropBoxMessage.Tag property.
Listing 16: Services.MessageTransformer.cs – MessageTransformer
Now that we have a list of drop box messages we need to attempt to locate the Account information for both the sender and receiver of the message. We will do this by creating the AccountMatchingService. This service communicates with our AccountRepository to get a list of AccountIDs by username and by email address. With the lists of IDs in hand we can then iterate through all of the drop box messages and hydrate their missing Account related information.
Listing 17: Services.AccountMatchingService.cs – AccountMatchingService
Finally we can build out our various {objectName}Services. This is another case where each service does something similar but to keep things separate is good (as this application will have to grow to be of any real use!). So we will take a look at the PostService knowing that each of the other services have similar methods on them for performing similar tasks (which you can look at in the source download). In this case we need a PostService.SavePosts method which will take a list of drop box messages, create a list of Post objects out of them, and then pass them to our PostRepository.SavePosts method.
Listing 18: Services.PostService.cs – PostService
We are finally to the point that we can start to piece our drop box application together. We will do this by creating a DropBoxProcessor class in the root of the DropBox project that has a Process method. Think of this as our entry point into the program similar to the Main method of a Console application. I am going to show you in list form what the Process method does as I have a bunch of try/catch stuff and logging aspects around the actual code.
Listing 19: DropBoxProcessor.cs – DropBoxProcessor
You may have noticed two things that caught you off guard or had you wondering in the above code listing: ConfigurationService.GetDeleteMesagesWhenComplete() and StatusMessage. The GetDeleteMessagesWhenComplete method is a new configuration value that allows you to put your application into a form of testing mode. Without this value, if you run the Process() method all of your test emails will be deleted! So you can now add a true or a false to this value to dictate if you want your messages deleted. The StatusMessage is beneficial for any sort of testing. We will use this in the drop box test harness project …which we can now build!
Yes, that is it. We now should have a fully functioning drop box processor that can read a pop3 server, download emails, parse them appropriately, and store the content to the appropriate area in the database server.
Building a drop box test harness
Man oh man…after all that code I bet you are hoping that there is not much more to this. Well…your wish is my command. Let’s add a new project to our solution. This time we will add a console application and name it DropBoxTestHarness. We will need to add a reference to the project so that we can communicate with our new DropBox application. Then in the Main method of the Program.cs file add the following lines of code.
Listing 20: Program.cs – Program
That is technically all there is to it. If you want you can debug into this application and take a look at the contents of the returned StatusMessage object. It will have a bunch of logging messages in it which should tell you right away if you are working or not. You will also have some output on your test harness console window. I took some screen shots of my debugger, console window, SQL query, and inbox to show the results.




Building a drop box monitor (windows service)
If you made it this far then I must say that you are quite the trooper! Also, if you made it this far you are probably wondering how in the heck you would deploy this into a production environment in a manner that it would run on its own every X minutes to clean out the drop box queue. Well that is exactly what this section is here to discuss. While we could leave the drop box test harness as it is and just run that as a scheduled task (which is technically feasible!) I figured it would be a bit more polished if we wrapped this tool set in a windows service.
For that reason let’s add a new project to your solution (yes…another one). This time we will add a windows service project to the solution. Name it DropBoxMonitor. Next, add a reference to the DropBox project as well as to System.Configuration. From there we have a couple of quick configuration tasks to perform. Open the properties of the project and change the namespace and assembly to AndrewSiemer.DropBoxMonitor. Then open the DropBoxMonitor.cs file (which should open into design view). Then in the properties window set the Name to DropBoxMonitor and ServiceName to DropBoxMonitor.
While still in the properties window of your DropBoxMonitor click Add Installer which is at the bottom of the pane. This should create a ProjectInstaller.cs which should also open up in design view. You should have two controls on the design surface already. A serviceProcessInstaller1 and a serviceInstaller1. This will be used when you install your service. Let’s configure each of them.
Select the serviceInstaller1. Then in the properties window enter a Description, DisplayName, and ServiceName. I entered “The drop box monitor watches a specified email address for distribution.”, “Drop Box Monitor”, and “DropBoxMonitor” for mine. These values will be used when you service is installed and is what will show up in the service management console. Then set the StartType to either Manual or Automatic depending on how you want your service to run. Automatic is best as this means if the server restarts the server will automatically restart with it.
Now click on your serviceProcessInstaller1 control on the ProjectInstaller design view. Make sure that the Account is set to LocalSystem and the Parent is set to ProjectInstaller.
Now you can close your ProjectInstaller. Re-open your DropBoxMonitor.cs file (if it is not still open). Right click on it and select View Code. Here is where we can specify our services behavior at start up, when it stops, etc. As a service runs behind the scenes so to speak we need to make some form of communication between our service and us. We will implement a quick LogService to perform this task.
Our LogService will be quick and to the point. It will have one method. This method will take a message and write it out to the file system. Specifically we will write to
To do this responsibly we should first check that this path actually exists before writing to it and if not we should create it.
Note: What if the server doesn’t have a C drive? I know I know…if the server doesn’t have a C drive this will still fail. I am not that paranoid. If you are then you can make the drive a configurable value!
From there we can open up a handle to the file that we are writing too, add a timestamp to the entry, and then write out the message.
Listing 21: LogService.cs – LogService
The other thing that we will need to create real quick is another ConfigurationService. This ConfigurationService is only concerned with one thing, how frequently does the service process our drop box queue. For that reason we need to add a linked reference to our app.config file in the src directory. Then we can add in this ConfigurationService code (which is the same as our other similar classes). Do notice that we have to multiply the value read from the app.config by 60000. This is because we need to convert from milliseconds to minutes to be more user friendly to our administrators!
Listing 22: ConfigurationService.cs – ConfigurationService
Now we can get back to our DropBoxMonitor. In the code view of our DropBoxMonitor we should have two methods, OnStart and OnStop. These are entry and exit points to this application. From here we can start a timer and control how frequently our drop box is processed. We can also do any sort of clean up that we might need to do.
In the very beginning of our DropBoxMonitor class we will add a Timer variable. This will live as long as our service is running.
Listing 23: DropBoxMonitor.cs – DropBoxMonitor
Next is our OnStart method which we will use to set up our timer as well as write to our log that our service is attempting to start and that it started successfully.
Listing 24: DropBoxMonitor.cs – DropBoxMonitor.OnStart
Notice in the listing that we hooked into the Timer.Elapsed event handler with our OnElapsedTime method. And that we pulled the GetMonitorFrequencyInMinutes value out of our ConfigurationService and assigned it to the Timer.Interval. This means that the timer will fire a notification to our OnElapsedTime method every {configured} amount of minutes.
Next let’s set up our OnStop method. This method will effectively stop our Timer and write to the log that the monitor has stopped.
Listing 25: DropBoxMonitor.cs – DropBoxMonitor.OnStop
Finally we can take a look at the OnElapsedTime method which is called each time the Timer’s Interval elapses. This method is responsible for writing to the log each time it starts. It then starts a StopWatch to keep track of how long clearing the queue takes. And then it calls into a Monitor class which we have not yet covered. Then it stops the StopWatch and writes more data to the log.
Listing 26: DropBoxMonitor.cs – DropBoxMonitor.OnElapsedTime
Now we can take a look at the Monitor class and ProcessQueue method mentioned above. First add a new class named Monitor to your projects root. Then add the ProcessQueue method. This method is responsible for calling out to our DropBoxProcessor that we built earlier. It then takes the resulting StatusMessage and writes all of its messages to the log.
Listing 27: Monitor.cs – Monitor
That is the entire application. Complete. But wait you are not done with your work. Now you need to install your service! First let’s build the solution. Then you need to open up a Visual Studio command prompt (start>programs>visual studio {version}>tools>command prompt). Then navigate to the location of your build output for the windows service. For me this is
Then you can enter the following commands:
Then hit enter. With any luck at all you will see a window similar to this:


Next we can open the Services Management Console. In there you should see your new Drop Box Monitor service waiting for you to start it up!
Now you can right click on your service and select Start. Your service should start and nothing! But wait. We configured the service to output some log file when it starts. Let’s go see if we have a new logging structure with a log in it. Not only do I have the appropriate file and folder structure:
But I also have the following log output:
Note: Why can’t I build my solution anymore? Do keep in mind that we installed your service directly from the build output directory. This means that it is running which means that your resources are physically in use. When you try to build on top of them you will get an error about not being able to access the files. In order to make changes and perform builds you will need to uninstall the service (using the same install command but with the –u argument).
Summary
Wow! We got a lot done in this article. In this article we created more extensive parsing features to implement tagging, account identification, and various other aspects. We then used our parsed data to match up the appropriate accounts for both our sending and receiving parties. We also took a look at how to extend the subject line in a way that we can allow our users to “tag” the emails that they send into our system. Once we had the bones of the drop box application running we created a test harness to prove that it worked as expected. Once we got the application physically running we then created a windows service wrapper around our drop box application so that it could be installed on a server and ran without direct supervision.
Please leave some comments regarding how you utilized this framework!
About Andrew Siemer
 |
I am a 33 year old, ex-Army Ranger, father of 6, geeky software engineer that loves to code, teach, and write. In my spare time (ha!) I like playing with my 6 kids, horses, and various other animals.
This author has published 29 articles on DotNetSlackers. View other articles or the complete profile here.
|
You might also be interested in the following related blog posts
Generic WPF Drag and Drop Adorner
read more
The CreateUserWizard and Validation ErrorMessages
read more
Search for Rich Internet Applications
read more
Building Interactive User Interfaces with Microsoft ASP.NET AJAX: Using the UpdatePanel
read more
CS Dev Guide: Emailing in Community Server 2007
read more
New Dynamic Data Controls ASP.NET : Nifty, But Not Real World
read more
UpdateControls 1.1: Bug Fixes and UpdateAction
read more
First Service Factory v3 Community Drop
read more
Hummingbird DM AEM: Automated Email Management
read more
Battery/Email Hack with Windows Mobile 5.0 SDK
read more
|
|
Please login to rate or to leave a comment.