Feeds:
Posts
Comments

Archive for the ‘Resolving Errors’ Category

Gmail requires SMTP connections to be secure. If you try to use log4net‘s SmtpAppender to connect to the Gmail smtp server and get an error like the following:

log4net:ERROR [SmtpAppender] Error occurred while sending e-mail notification.
System.Net.Mail.SmtpException: The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required. Learn more at
   at System.Net.Mail.MailCommand.CheckResponse(SmtpStatusCode statusCode, String response)
   at System.Net.Mail.MailCommand.Send(SmtpConnection conn, Byte[] command, String from)
   at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, SmtpFailedRecipientException& exception)
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at log4net.Appender.SmtpAppender.SendEmail(String messageBody)

the most common cause is failure to add the authentication line to your configuration:

<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
	<to value="foo@bar.com" />
	<from value="baz@bar.com" />
	<subject value="Some subject" />
	<smtpHost value="smtp.gmail.com" />
	<authentication value="Basic" />
...

If you try to connect to gmail without SSL you will receive a message like the following:

log4net:ERROR [SmtpAppender] Error occurred while sending e-mail notification.
System.Net.Mail.SmtpException: The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.0 Must issue a STARTTLS command first. o47sm1936887yhn.72
   at System.Net.Mail.MailCommand.CheckResponse(SmtpStatusCode statusCode, String response)
   at System.Net.Mail.MailCommand.Send(SmtpConnection conn, Byte[] command, String from)
   at System.Net.Mail.SmtpTransport.SendMail(MailAddress sender, MailAddressCollection recipients, String deliveryNotify, SmtpFailedRecipientException& exception)
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at log4net.Appender.SmtpAppender.SendEmail(String messageBody)

In this case the problem is the latest official release of log4net (version 1.2.10 at the time of this posting) does not provide a way to configure the SmtpAppender to send mail using SSL.

It turns out a fix for this problem was checked in to the log4Net subversion repository in June 2008 but no official build contains the fix.

One solution is to get the latest log4net source code from its subversion repository, compile for .Net 2.0, and you’re in business… but that might cause you other headaches if they unexpectedly changed something else that you were using.

The alternative is to download the source of the latest public release (1.2.10) and patch it yourself as follows:

The fix involves making two small changes to the log4net code, and adding a corresponding value to your log4net configuration.

1) download the source code from the Apache web site
2) unzip it
3) open the sln file (under src) with Visual Studio
4) find the SmtpAppender class (under log4net/Appender)
5) search in that class for “public MailPriority Priority”
6) add the following new property after that it:

public bool EnableSsl { get; set; }

7) search for “smtpClient.Send(mailMessage)”

Notice that this segment of code is grayed-out. That’s because the project has a conditional compilation symbol named NET_1_0 that is enabled by default and this code segment is enclosed in a conditional compilation symbol named NET_2_0. We need to enable this segment of code. To do that:

7a) right click on the log4net project in the solution explorer and select “Properties”
7b) change the conditional compilation symbol version

screen shot of changing the compilation symbol to NET_2_0

7c) close the properties tab
7d) the code segment should no longer appear grayed-out
7e) above the “smtpClient.Send” line you searched for add the following:

	smtpClient.EnableSsl = EnableSsl;

8 ) when you try to compile you’ll get an error in XmlConfigurator related to System.Configuration.ConfigurationManager. This is because the project does not have a reference to the System.Configuration assembly. Add the reference.

9) you’ll also get an error related to a missing NUnit reference in the test project. You can add one and run the tests – several fail by the way but none are related to the change we made, they were checked in that way. Seriously. Anyway, you could also skip that part and compile only the log4net project.

10) replace the log4net assembly in your project with the one from build\bin\net\1.0\debug

11) update the SmtpAppender segment of your app.config to include the EnableSsl setting

<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
	<to value="foo@bar.com" />
	<from value="baz@bar.com" />
	<subject value="Some subject" />
	<smtpHost value="smtp.gmail.com" />
	<authentication value="Basic" />
	<port value="587" />
	<username value="gmail user name" />
	<password value="gmail password" />
	<bufferSize value="1" />
	<EnableSsl value="true"/>
	<lossy value="true" />
	<evaluator type="log4net.Core.LevelEvaluator">
		<threshold value="ERROR"/>
	</evaluator>
	<layout type="log4net.Layout.PatternLayout">
		<conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" />
	</layout>
</appender>

12) recompile your project if necessary
13) trigger whatever it is that you expect to cause something to be logged to log4net and it should work.

If it still doesn’t work, make sure you have a reference to SmtpAppender in one of your configured log4net categories, and/or in the root category.

<root>
    <level value="WARN"/>
    <appender-ref ref="RollingLogFileAppender"/>
    <appender-ref ref="SmtpAppender"/>
</root>

And that the log level you are using in your code is at least as high as the highest one configured in the SmtpAppender and related category.

...
	<lossy value="true" />
	<evaluator type="log4net.Core.LevelEvaluator">
		<threshold value="ERROR"/>
	</evaluator>
	<layout type="log4net.Layout.PatternLayout">
		<conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" />
	</layout>
</appender>
<root>
    <level value="WARN"/>
    <appender-ref ref="RollingLogFileAppender"/>
    <appender-ref ref="SmtpAppender"/>
</root>

Read Full Post »

While pulling the images from an Exif formatted Canon camera flash memory card I noticed this off-by-one error in the way the images are stored.

This is an interesting bug. Think about the code behind this problem for a moment. If we were writing this from scratch, we might start like this:

[Test]
public void Should_increment_the_image_number()
{
    _imageNumber = 0;
    int next = GetNextImageNumber();
    next.ShouldBeEqualTo(1);
    _imageNumber.ShouldBeEqualTo(1);
}

[Test]
public void Should_reset_the_image_number_to_1_given_9999()
{
    _imageNumber = 9999;
    int next = GetNextImageNumber();
    next.ShouldBeEqualTo(1);
    _imageNumber.ShouldBeEqualTo(1);
}

with implementation

private volatile int _imageNumber;

private int GetNextImageNumber()
{
    _imageNumber = _imageNumber + 1;

    if (_imageNumber > 9999)
    {
        _imageNumber = 1;
    }
    return _imageNumber;
}

Next we’ll want to handle incrementing the directory number.

[Test]
public void Should_increment_the_directory_number()
{
    _directoryNumber = 100;
    IncrementDirectoryNumber();
    _directoryNumber.ShouldBeEqualTo(101);
}

[Test]
public void Should_reset_the_directory_number_to_100_given_999()
{
    _directoryNumber = 999;
    IncrementDirectoryNumber();
    _directoryNumber.ShouldBeEqualTo(100);
}

with implementation

private volatile int _directoryNumber;

private void IncrementDirectoryNumber()
{
    _directoryNumber = _directoryNumber + 1;
    if (_directoryNumber > 999)
    {
        _directoryNumber = 100;
    }
}

Now when the image number crosses to the next 100 we have to increment the directory number.

[Test]
public void Should_increment_the_directory_number_when_the_image_number_goes_to_the_next_hundred()
{
    _imageNumber = 99;
    _directoryNumber = 100;
    int next = GetNextImageNumber();
    next.ShouldBeEqualTo(100);
    _imageNumber.ShouldBeEqualTo(100);
    _directoryNumber.ShouldBeEqualTo(101);
}

private int GetNextImageNumber()
{
    if (_imageNumber % 100 == 99)
    {
        IncrementDirectoryNumber();
    }
    _imageNumber = _imageNumber + 1;

    if (_imageNumber > 9999)
    {
        _imageNumber = 1;
    }
    return _imageNumber;
}

And lastly we need to build the file path.

[Test]
public void Should_get_path__100CANON_IMG_0002__starting_with_directory_number_100_and_image_number_1()
{
    _directoryNumber = 100;
    _imageNumber = 1;
    var path = GetNextImagePath();
    path.ShouldBeEqualTo(@"100CANON\IMG_0002");
    _directoryNumber.ShouldBeEqualTo(100);
    _imageNumber.ShouldBeEqualTo(2);
}

public string GetNextImagePath()
{
    return String.Format(
        @"{0:000}CANON\IMG_{1:0000}",
        _directoryNumber,
        GetNextImageNumber());
}

All tests pass so we’re done right? Nope. The following test fails (as expected) given the values from my image above.

[Test]
public void Should_get_path__320CANON_IMG_2000__starting_with_directory_number_319_and_image_number_1999()
{
    _directoryNumber = 319;
    _imageNumber = 1999;
    var path = GetNextImagePath();
    path.ShouldBeEqualTo(@"320CANON\IMG_2000");
    _directoryNumber.ShouldBeEqualTo(320);
    _imageNumber.ShouldBeEqualTo(2000);
}

Did you cringe/notice when we wrote the code that introduced the bug? If not, you might find the answers to this stack exchange question enlightening.

There are two routes to fixing this problem, the easy way and the correct way. The easy way is:

public string GetNextImagePath()
{
    var imageNumber = GetNextImageNumber();
    return String.Format(
        @"{0:000}CANON\IMG_{1:0000}",
        _directoryNumber,
        imageNumber);
}

The correct way is to remove the side effect so that the method becomes:

public string GetNextImagePath()
{
    IncrementImageNumber();
    return String.Format(
        @"{0:000}CANON\IMG_{1:0000}",
        _directoryNumber,
        _imageNumber);
}

… a coding problem you might use as a refactoring TDD Kata.

Read Full Post »

I encountered this NUnit message in a test fixture that had the following method:

	[TearDown]
	private void AfterEachTest()
	{
		_repository.VerifyAllExpectations();
	}

NUnit doesn’t allow methods decorated with [SetUp] or [TearDown] attributes to be private. Change the access to public or protected to resolve the problem.

Read Full Post »

If you get an error like the following on your build server:

error MSB4019: The imported project “C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets” was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

You have two options. You could copy Microsoft.WebApplication.targets from your development box, or you could install Visual Studio on the build server. The simplest solution is to copy the file, making sure to reproduce the directory structure exactly.

Read Full Post »

After installing ruby 1.8.6 on Windows 7 I tried to install rake and received this error:

C:\>gem install rake
ERROR:  While executing gem ... (Zlib::GzipFile::Error)
    not in gzip format

It was annoying to resolve so I’m posting what worked for me.

Find out where your ruby is configured to look for sources:

C:\>gem sources
*** CURRENT SOURCES ***

http://gems.rubyforge.org/

If it is pointed at gems.rubyforge.org (which it is when first installed) then you’re pointed at the old web server so when ruby tries to get updates it gets an HTTP redirect (302) as a response instead of the expected data in GZIP format. It apparently doesn’t have an error handler configured to detect the redirect so it just gives up.

To fix it you have to update the list of sources. First add the correct source:

C:\>gem sources -a http://rubygems.org/
http://rubygems.org/ added to sources

Then remove the deprecated one:

C:\>gem sources -r http://gems.rubyforge.org/
http://gems.rubyforge.org/ removed from sources

C:\>gem sources
*** CURRENT SOURCES ***

http://rubygems.org/

Next update your ruby system:

C:\>gem update --system
Updating RubyGems
Updating rubygems-update
Successfully installed rubygems-update-1.3.7
:0:Warning: Gem::SourceIndex#search support for String patterns is deprecated
Updating RubyGems to 1.3.7
Installing RubyGems 1.3.7
RubyGems 1.3.7 installed

=== 1.3.7 / 2010-05-13

NOTE:

http://rubygems.org is now the default source for downloading gems.

You may have sources set via ~/.gemrc, so you should replace
http://gems.rubyforge.org with http://rubygems.org

http://gems.rubyforge.org will continue to work for the forseeable future.
...

Note that update verifies that the old source URL is no longer valid…

You should now be able to continue your installation, which in my case was rake.

C:\>gem install rake
Successfully installed rake-0.8.7
1 gem installed
Installing ri documentation for rake-0.8.7...
Installing RDoc documentation for rake-0.8.7...

Read Full Post »

I use NHibernate with Json.NET and noticed that I was getting inexplicable “__interceptors” properties in my serialized objects. A google search turned up this excellent solution by Lee Henson which I adapted to work with Json.NET 3.5 Release 5 as follows.

    public class NHibernateContractResolver : DefaultContractResolver
    {
      private static readonly MemberInfo[] NHibernateProxyInterfaceMembers = typeof(INHibernateProxy).GetMembers();

      protected override List<MemberInfo> GetSerializableMembers(Type objectType)
      {
        var members = base.GetSerializableMembers(objectType);

        members.RemoveAll(memberInfo =>
                          (IsMemberPartOfNHibernateProxyInterface(memberInfo)) ||
                          (IsMemberDynamicProxyMixin(memberInfo)) ||
                          (IsMemberMarkedWithIgnoreAttribute(memberInfo, objectType)) ||
                          (IsMemberInheritedFromProxySuperclass(memberInfo, objectType)));

        var actualMemberInfos = new List<MemberInfo>();

        foreach (var memberInfo in members)
        {
          var infos = memberInfo.DeclaringType.BaseType.GetMember(memberInfo.Name);
          actualMemberInfos.Add(infos.Length == 0 ? memberInfo : infos[0]);
        }

        return actualMemberInfos;
      }

      private static bool IsMemberDynamicProxyMixin(MemberInfo memberInfo)
      {
        return memberInfo.Name == "__interceptors";
      }

      private static bool IsMemberInheritedFromProxySuperclass(MemberInfo memberInfo, Type objectType)
      {
        return memberInfo.DeclaringType.Assembly == typeof(INHibernateProxy).Assembly;
      }

      private static bool IsMemberMarkedWithIgnoreAttribute(MemberInfo memberInfo, Type objectType)
      {
        var infos = typeof(INHibernateProxy).IsAssignableFrom(objectType)
                      ? objectType.BaseType.GetMember(memberInfo.Name)
                      : objectType.GetMember(memberInfo.Name);

        return infos[0].GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length > 0;
      }

      private static bool IsMemberPartOfNHibernateProxyInterface(MemberInfo memberInfo)
      {
        return Array.Exists(NHibernateProxyInterfaceMembers, mi => memberInfo.Name == mi.Name);
      }
    }

To use it just put an instance in the ContractResolver property of your JsonSerializer. The circular dependency problem noted by jishi can be resolved by setting the ReferenceLoopHandling property to ReferenceLoopHandling.Ignore . Here’s an extension method that can be used to serialize objects using Json.Net

      public static void SerializeToJsonFile<T>(this T itemToSerialize, string filePath)
      {
        using (StreamWriter streamWriter = new StreamWriter(filePath))
        {
          using (JsonWriter jsonWriter = new JsonTextWriter(streamWriter))
          {
            jsonWriter.Formatting = Formatting.Indented;
            JsonSerializer serializer = new JsonSerializer
              {
                NullValueHandling = NullValueHandling.Ignore,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                ContractResolver = new NHibernateContractResolver(),
              };
            serializer.Serialize(jsonWriter, itemToSerialize);
          }
        }
      }

History

Read Full Post »

%d bloggers like this: