danludwig
danludwig

Reputation: 47375

Two different implementations of System.Net.Mail.SmtpSender Dispose(bool)?

Thank goodness for R#7. Without their new "go to decompiled sources" feature, I would be at a loss for how to describe this issue.

I have had a certain SmtpMailSender implementation class for a while now. Here are a couple of things it does:

1.) It does not send network mail in development mode. The development web.config looks like this:

<smtp deliveryMethod="SpecifiedPickupDirectory">
    <specifiedPickupDirectory pickupDirectoryLocation="App_Data/mail" />
</smtp>
<!--<smtp deliveryMethod="Network">
    <network host="smtp.roadrunner.com" />
</smtp>-->

The mail sending class sniffs the SmtpClient.DeliverMethod property, and configures the real runtime path of the SmtpClient.PickupDirectoryLocation (to something like "C:\path\to\project\App_Data\mail").

2.) It wraps all of the sending code into a using statement and a try block:

...
try
{
    using (var smtpClient = new SmtpClient())
    {
        // detect pickup directory
        // do other encapsulated behaviors
        smtpClient.Send(message);
    }
}
catch (Exception ex)
{
    _exceptionLogger.LogException(ex);
    if (++retryCount  > 2) throw;
    Thread.Sleep(3000);
    Send(message, retryCount); // recursive to same method
}

This has all been working great on my main workstation since last year. I downloaded the project onto my laptop though, and kept seeing that every SmtpClient.Send(MailMessage) was causing the following exception:

InvalidOperationException: "The SMTP host was not specified."
at System.Net.Mail.SmtpClient.CheckHostAndPort()
at System.Net.Mail.SmtpClient.get_ServicePoint()
at System.Net.Mail.SmtpClient.Dispose(Boolean disposing)
at System.Net.Mail.SmtpClient.Dispose()
at My.ImplementationOf.SmtpMailSender.Send(MailMessage message, Int32 retryCount)

The exception was being thrown from SmtpClient.CheckHostAndPort, which throws either when the SmtpClient.Host property is null or zero length according to the R# decompilation on my laptop. I went back to my workstation and found that even though the smtpClient.Host property was null, this exception was not being thrown.

Then I used R#'s little decompile feature for System.Net.Mail.SmtpClient on the workstation and found that there are 2 different implementations of this class! Very strange, because the reference to System.dll is pointing at C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.dll on both machines! Basically they are the same, with one important difference:

protected virtual void Dispose(bool disposing)
{
    // the workstation decompilation shows this:
    if (this.transport != null && this.servicePoint != null)
        this.transport.CloseIdleConnections(this.servicePoint);

    // but the laptop decompilation shows this:
    if (transport != null)
        transport.CloseIdleConnections(ServicePoint);
}

HOW CAN THERE BE TWO DIFFERENT IMPLEMENTATIONS OF THIS?

Updates

Both machines are showing Windows 7 Professional Service Pack 1. I ran Windows Update on both and both are telling me the computer is up to date. The only difference I can think of is that the laptop's Windows 7 has not yet been activated, I just installed it 3 days ago. I wonder, could activation of the OS change the framework's System.dll?

I then took these steps:

  1. Activated Windows on the laptop
  2. Rebooted
  3. Ran Windows Update and found everything was still up to date.
  4. Ran the project scenario and found that the same exception is still being thrown.

Upvotes: 3

Views: 1916

Answers (2)

Joe Strommen
Joe Strommen

Reputation: 1234

Probably because one machine has .NET 4.5 and the other does not. Have you installed VS2012 onto your main workstation?

This bug was fixed in .NET 4.5:

http://connect.microsoft.com/VisualStudio/feedback/details/618568/smtpclient-and-dispose-without-a-hostname-gives-invalidoperationexception

And installing .NET 4.5 overwrites new DLLs on top of your existing .NET 4.0 dlls:

http://www.west-wind.com/weblog/posts/2012/Mar/13/NET-45-is-an-inplace-replacement-for-NET-40

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1501926

IIRC, service packs to the framework don't bump the assembly versions. I could be wrong, but the first thing I'd check is the service pack level of each machine.

Of course, there are hotfixes which wouldn't show as clearly as service packs...

Upvotes: 0

Related Questions