Thursday 14 July 2011

Non expected exception on IPAddress.TryParse

Lately, for the one of our client we implemented a functionality which uses Geo Location as a basic visitor recognition. The problem appeared after the functionality had been promoted to the live environment - it simple did not work. After a quick investigation we founded that the problem is caused by Akamai which acts as a proxy for whole domain.

The solution itself is pretty simple. Akamai can be configured so that it sends additional Http Request Header with original IP. I just thought that some basic validation on this header value would be great, so I have added something like code below:
var headerIp = request.Headers["True-Client-IP"];
IPAddress akamaiIpAddress = IPAddress.None;
var isValidIp = IPAddress.TryParse(headerIp, out akamaiIpAddress);

As you can see I laveraged on IpAddress class to determine whether sent header is correct. The problem was that if there was no header I had had the exception on that line. Why? The answer is very simple, and very unexpected - you can not pass null as a first parameter. I changed this line slightly in the following manner:

var headerIp = request.Headers["True-Client-IP"] ?? string.Empty;

and problem disappeared. I always thought that TryParse method on any object should swallow any exception, because it is expected from it. This is one of the most deceiving thing I have met in .NET. Does anyone know if any other TryParse method potentially throws exceptions as well?

Monday 23 May 2011

Integrate Sitecore.Logging with Castle Windsor


Abstract
A couple of months ago I started using Dependency Injection pattern in my projects more consciously and extensively. Initially it was not easy and comfortable, however I found it very profitable and useful. I picked Windsor as a Inversion of Control container. In the same time Sitecore had come along as a new Web CMS platform in Cognifide range. As a natural consequence those two got married in my projects.

The issue
The first problem I encountered was a logging issue. I'm using the Logging Facility so that I don't need reference to log4net library, using ILogger from Castle.Core.Logging namespace. Using this facility has a big advantage - Windsor resolves current logger context automatically for maintained classes, so that you don't have to worry about it. If you would like to obtain current logger directly from container you can resolve ILoggerFactory, which creates a logger instance for you. However, this is not a case here. The case was that while everything seemed to be fine, no logs appeared, moreover Windsor always returned a default logger.

After some investigation I finally found the reason - apparently Sitecore guys took whole log4net project as is, changed it according to their requirements (please note that there are some additional configuration features in Sitecore log4net logging configuration section) and finally embraced it as a Sitecore.Logging library. This causes that Windsor is unable to create any logger instance, because it uses full class name to resolve types (note that there is no log4net library anymore, you have Sitecore.Logging instead).

The solution is simple and pretty straightforward. First you should read great Michael Edward's post where he explains why logging doesn't work by default. However I would like to go one step ahead and keep my custom functionality "Sitecore free". Therefore I would like to keep using ILogger and by that be free from additional dependency like log4net or Sitecore.Logging. To achieve my goal I had to register my own facility just like in Michael's post, then I had to write my own custom ILoggerFactory and ILogger implementations. Both are very simple , for example ILoggerFactory has four methods and one of them is
public ILogger Create(string name)
{
return new SitecoreLogger(log4net.LogManager.GetLogger(name));
}
where SitecoreLogger is ILogger implementation. Please note that I pass internal logger in constructor so that I can leverage on it in my implementation. In fact, it is only a wrapper for native logger. ILogger has a number of various methods and each of them is similar to written below:
public void Error(string message, Exception exception)
{
InnerLogger.Error(message, exception);
}
To use it you have to add a custom facility, the simplest way is doing that from code, where you simply indicate that logger should be created by a custom factory:
container.AddFacility(p => p.LogUsing<SitecoreLoggerfactory>().WithAppConfig());
where container is a IWindsorContainer instance, and log4net configuration is in web.config file. You can register it like Michael proposed in his post from configuration file as well.
Conclusion
Solution above allows me to use logging in a loosely coupled way, and keep my custom functionalities as intended - clean and free from unnecessary dependencies. This code is fully open source so feel free to download and use it or adjust it in your project.

Refrences