Click here to Skip to main content
15,884,629 members
Articles / Web Development / ASP.NET

Using SSL with System.Web.Management.MailWebEventProvider

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
25 Oct 2007CPOL3 min read 19.7K   13  
The Decorator pattern meets Reflection in a workaround to enable SSL for ASP.NET health monitoring e-mail event providers.

Introduction

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.

As has been discovered by countless people, while the new SmtpClient() class in ASP.NET 2.0 is neat, easy to use, and configurable via Web.Config, they forgot one thing to make it 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 do 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.

Background

I hit the wall, really hard, trying to use the System.Web.Management.TemplatedMailWebEventProvider class for the development of my Online Password Manager, Xecrets. 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 ain't 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).

The code

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

C#
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(); 
    } 
}

What's left to do?

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!

You must also register your provider in Web.Config, of course.

The morale of the story

One of the morals 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.

History

This is the first version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer Axantum Software AB
Sweden Sweden
I've been working with all aspects of software development since 1979 - from compiler construction to management. Currently I'm an independent consultant mostly specializing in computer security. Please see my homepage for contact details.

I speak C like a native, and have a pretty good grasp of C++. The most recent five years C# has been the main development language. Traditionally Unix has been the dominating environment, but currently the scales have tipped over to Windows, due to market demands but I'm equally at home developing in both environments.

When I'm not coding I'm usually sitting on one of my 4 bikes, indoors or outdoors, on the road or in the woods.

Comments and Discussions

 
-- There are no messages in this forum --