Solution Explorer Recently I had to send an email blast out to about two thousand email subscribers from a client's ASP.NET Web Forms application. The client had an admin form where they would compose and send out the email. Unfortunately, with that many emails the Web form would inevitably hang. Plus, with Exchange Server there is no easy way to know how many emails actually got sent; you could use Powershell to determine this or you could log it but it still isn't a robust way of doing things.

The conventional wisdom is to use a third party service for mass mailings and most times this is probably your best option. In this situation, an email blast is only sent every 5 years so it really didn't make sense to enrol in a monthly plan. With a little due diligence, this can be accomplished with a very simple console application which can be called from the Web form to dispatch the emails.

The basic design is that the subject line and email body text are entered in the form and passed to the console application as string parameters. In the console app, we can obtain the email addresses from a database and send the emails out in batches with a pause between each batch.

Some basics first: the entry point to any console application is the Main method:

// Mailer class in console application

static void Main(string[] args)
    if (args.Length >= 2)
        SmtpClient smtpClient = new SmtpClient(EMAIL_HOST);
        smtpClient.Host = "localhost";

        MailMessage message = new MailMessage();
        message.Priority = MailPriority.High;
        message.Subject = args[0];
        message.Body = args[1];
        smtpClient.Send(FROM_ADDRESS, TO_ADDRESS, message.Subject, message.Body);

The array of strings args parameter corresponds directly to the command line parameters passed to the console application; string[0] is the first parameter, strg[1] is the second parameter and so on. This is different in C and C++, where the name of the console application itself is the first parameter... when in doubt, try it out!

Note that when testing this on the command line initially, that there is a limitation on the size of the strings you can pass. This will not apply when sending the parameters programmatically from the Web form code-behind. You can test that your console app is sending emails by creating a drop folder on your C drive. Download and install Live Mail to view the .eml files generated. You can create a dummy gmail account to get this running and choose not to make Live Mail your default email client during the install (if this is your preference). This is a really simple and useful way to test email functionality locally on your dev machine. Just update your Web.Config file with the following to get it working:

        <smtp deliveryMethod="SpecifiedPickupDirectory">
            <specifiedPickupDirectory pickupDirectoryLocation="c:\maildrop" />

To generate a test email with the console app and pass the subject and body parameters, call it like this:

// DOS command line

C:\>ConsoleApplication1 "Subject Line Text" "Some body text"

To call the console app from the Web form code-behind we use the Process.Start method. We can avail of the ProcessStartInfo class to set up any properties in advance of making the process call.

// Web form code-behind
// Pass subject and message strings as params to console app

ProcessStartInfo info = new ProcessStartInfo();

string arguments = String.Format(@"""{0}"" ""{1}""",
     subjectText.Text.Replace(@"""", @""""""),
     messageText.Text.Replace(@"""", @""""""));
info.FileName = MAILER_FILEPATH;
info.Arguments = arguments;

We also need to take account of the possibility of quotes being included in the subject line or body text. I enlisted some help on this issue with a StackOverflow question. The solution was a combination of composite string formatting and verbatim "@" string literals. See the String.Format call in the code snippet above.


Email Form

If you've been testing the console app and then go on to debugging with VS, you may come up against a file locking issue. This issue is a known bug - I've seen bug reports going back to 2006 on this one.

Error 9 Unable to copy file "obj\x86\Debug\ConsoleApplication1.exe" to "bin \Debug\ConsoleApplication1.exe". The process cannot access the file 'bin\Debug\ConsoleApplication1.exe' because it is being used by another process.



There are two workarounds to this. My way is to close out VS and then kill any remaining processes for the console app: Windows Task Manager -> Processes tab -> Show processes from all users -> right- click each process and kill it (End Process). The second method is to add a pre-build script.

Tags: , ,


Incorrect Format


Here's the scenario: I'm building a basic 3-layer Web application for a client with business and data layers. Queries are performed in stored procedures, just basic ADO.NET. The table I am attempting to insert a record into has a range a field types such as strings, ints, decimals, etc.

If the user is entering integer or decimal values via texboxes, which is usually the case, then you have to expect either no data or a string of possibly mal-formed data. You must filter out the mal-formed data with validation and/or convert the resulting input data to the expected database type.

If you have a database field called SquareFeet of type int and you attempt to insert the following in your code-behind insert method, you will probably see this error:

// Results in error message
AddSomething(int squareFeet)


You must be careful if you are trying to fetch, say, an int or decimal as input:

// Correct way if SquareFeet field is an int
int squareFeet
if (int.TryParse(squareFeetTxt.Text.Trim(), out squareFeet))
    squareFeet = Convert.ToInt32(squareFeetTxt.Text.Trim());
     squareFeet = 0;
// Now insert the value as part of the record


// Correct way if SquareFeet field is a decimal
int squareFeet
if (decimal.TryParse(squareFeetTxt.Text.Trim(), out squareFeet))
    squareFeet = Convert.ToDecimal(squareFeetTxt.Text.Trim());
     squareFeet = 0.0m;
// Now insert the value as part of the record



Refer to these links for the differences between Convert.ToInt, int.Parse and Int.TryParse:

Refer to this link for an explanation of the 0.0m decimal syntax:

Moral of the Story
If you are learning any language, your first priority must be to understand the types thoroughly. Resist the temptation to gloss over the grammar just to get to the fancy stuff! :-)

Tags: , ,


C# 4.0 is the next version of the C# language being shipped with VS 2010. Personally, I'm still coming to terms with Generics as introduced in C# 2.0 and LINQ which came with 3.0. Anders Hejlsberg touched on the Covariance/Contravariance topic in his TechEd presentation in LA last month entitled "The Future of C#".

Evolution of C# - Anders Hejlsberg


The terms Invariance, Covariance and Contravariance are not by any means new. Anyone coming from a computer science background will have encountered the terms. Prior to attending Anders' session, I hadn't given this much conscious thought in a long time - we tend to know what we can and can't do within the syntactical constraints of a language - and tend not to question things further. However, in C# 4.0, delegates and interfaces will play nicer when working with generics. So much attention is likely to be focused on the dynamic programming additions in C# 4.0 (mainly in support of LINQ), that this addition may go unnoticed.

Variance in C# 4.0 - Anders Hejlsberg - Anders Hejlsberg



Invariant: A return parameter is invariant if we must use the exact match of the type name. In other words, neither covariance nor contravariance is permitted

Covariant: A parameter is covariant if we can use a more derived type as a substitute for the parameter type. In other words, a subclass instance can be used where a parent class instance was expected.

Contravariant: A return value is contravariant if we can assign the return type to a variable of a less derived type than the parameter. In other words, a super class instance can be used where a subclass instance was expected.

Variance in C# 4.0 - Anders Hejlsberg - Anders Hejlsberg


Generally, C# supports covariant parameters and contravariant return types. There has always been support for covariance and contravariance in C# - C# 4.0 will just ensure that generic delegates and interfaces will also behave they way we would expect.

Eric Lippert is the developer responsible for this feature of the C# 4.0 release and has an eleven-part blog series on just this topic. I would also recommend reading Charlie Calvert's article on this topic for some code samples.

Side Note: You do not need VS 2010 to experiment with these features - just download the framework to a test VM.

Tags: , ,

.NET 4.0 | C#