Wednesday, October 24, 2007

Troubles with Health Monitoring, System.Net.Mail.SmtpClient and SSL

The web is full of desperate pleas for help by prematurely bald developers who have discovered the fatal flaw in the shiny new ASP.NET 2.0 System.Net.Mail.SmtpClient class. This is touted as overcoming all the problems of the old variant, that could not even be configured for credentials without resorting to some heavy-duty tricks.

However, as has been discovered by countless people, while the new SmtpClient() class is neat, easy to use, and configurable via Web.Config - they forgot one thing to make configurable. The EnableSsl property is not settable via Web.Config. So big deal you say - just write a line of code and set it manually... Problem is - you frequently did not write the code that instantiates the SmtpClient. The most well known problem is with the suite of new login controls, which have the capability of sending mail in some circumstances. Works fine - unless you need to enable SSL for the SMTP connection. Fortunately, there's a well-known workaround since these controls expose an event called SendingMail, where you can do magic things including affecting how the mail is sent - most simply by taking over responsibility of sending it.

Then I hit the wall, really hard, trying to use the System.Web.Management.TemplatedMailWebEventProvider class. This is a provider that can subscribe to health monitoring events, and send them via e-mail. Using SmtpClient() of course, with the instantiation hidden deep in its innards of sealed and internal classes in System.Web.dll. No events to the rescue this time either.

After hours of fruitless searching, I finally come to the conclusion that I needed a work-around, ugly as it may be. So, here's where the decorator pattern meets reflection. Sigh. It aint pretty, but it does work, and I do get to use the otherwise rather nice and advanced TemplatedMailWebEventProvider (the same technique can be used for the SimpleMailWebEventProvider, or any provider derived from MailWebEventProvider).

In the end, it's just a few lines of code (comments and veritical white space removed for brevity):

using System; using System.Collections.Specialized; using System.Reflection; using System.Web.Management; public class TemplatedMailWithSslWebEventProvider : WebEventProvider {     private TemplatedMailWebEventProvider _templatedProvider;         public TemplatedMailWithSslWebEventProvider()     {         ConstructorInfo constructor = typeof(TemplatedMailWebEventProvider)             .GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,                             null, new Type[0], null);         _templatedProvider = (TemplatedMailWebEventProvider)constructor             .Invoke(null);     }     public override void Initialize(string name, NameValueCollection config)     {         if (config == null)         {             throw new ArgumentNullException("config");         }         _templatedProvider.Initialize(name, config);         FieldInfo field = typeof(MailWebEventProvider)             .GetField("_smtpClient",                       BindingFlags.Instance | BindingFlags.NonPublic);         field.SetValue(_templatedProvider, new SmtpClientWithSsl());     }     public static MailEventNotificationInfo CurrentNotification     {         get         {             return TemplatedMailWebEventProvider.CurrentNotification;         }     }     public override void Flush()     {         _templatedProvider.Flush();     }     public override void ProcessEvent(WebBaseEvent raisedEvent)     {         _templatedProvider.ProcessEvent(raisedEvent);     }     public override void Shutdown()     {         _templatedProvider.Shutdown();     } }
All that's left for you to do is to define the SmtpClientWithSsl() class, deriving from System.Net.Mail.SmtpClient() whose developer probably by the same oversight that forgot about SSL, also forgot to make it sealed. Fortunately. Here two wrong almost makes one right!

One of the morales of this story is to really think about the use of sealed and internal. My first try was to implement a custom templated e-mail provider, but it turns out that was quite a job, and I could not override or use anything from System.Web.dll because it was all sealed and used lots of internal helpers. If you really need to hide the implementation that bad, it might be better to introduce a public base class, where the essential interfaces are exposed as protected methods and properties. When you limit a class to sealed, and it depends on lots of additional logic, do consider making that logic available at least to alternative implementations and give it a base to inherit from.

Tuesday, October 16, 2007

Book Review: HTML, XHTML, and CSS Bible, 3rd Edition

HTML, XHTML, and CSS Bible, 3rd Edition, by Bryan Pfaffenberger, Steven M. Schafer, Chuck White and Bill Karow, Wiley Publishing, Inc. ISBN 0-7645-5739-4.

Not being really a GUI person, I tend to thrive more on the backend of things with threads, algorithms and such, I still need to do a fair bit of client side stuff. With this in mind, I purchased this book thinking that an authoritative work like a bible was just what I needed.

However, this is not a bible. Not at all. It's a very broad introduction on a broad range of subjects with very little depth. Why it has XHTML in the title is totally beyond me, there's not even a chapter about it. This book is really about HTML, CSS and the web in general - forget XHTML (although admittedly there is little difference from HTML).

In the preface, it's mentioned that the main author, Bryan Pfaffenberger is the author of more than 75 books. Impressive! Until you actually read this one. I have never seen so many mistakes in one book. Nor have I seen such blatant waste of space and duplication of code. Seriously, you're paying for about 50 pages of Lorem Ipsum here!

So, it's sloppily written, wasteful of dead trees and is mistitled. Is it thus useless? No, actually not really.

If you really don't think you can use this bible as a reference (because of all the mistakes etc), you can probably get some pretty good use out of it if you're relatively new to the web, but can code a little, and you're thinking about starting your own web site for whatever reason. It does cover a wealth of topics which are relevant as an introduction. There are chapters about how to upload your site, how to optimize for search engines etc etc - none of which is implied by the title, but still useful for a different reader.

I would like to rename it to "Getting Started with the Web" or something like that. As such, it's not really that bad. But don't buy this if you're looking for detailed in-depth information about HTML, XHTML and CSS.