Logging With Log4Net

Jumping back to a bit of .Net development this week.

As techniques go, logging is one of the simplest and most useful in a developer's toolbox. Once your code is out and running in the wild, it becomes a lot harder to track down issues without being able to jump into the debugger. Logging to the rescue!

There are a number of logger implementations for the .Net Framework, including nLog, Microsoft's Enterprise Library, and my personal choice, log4net.

log4net is a very flexible logging library that provides the ability to log to a number of different outputs, which can be changed easily through configuration files, even at run time.

Setting Up

In your AssemblyInfo.cs add the following to have the config picked up:
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Log4Net.config", Watch = true)]

Specifying the watch option will cause log4net to monitor the configuration file for changes. This is fantastically useful, allowing you to change the logging level dynamically without needing to restart your application.

Speaking of configuration, add a file named log4net.config to the root of your project:







This specifies a logger that will output to a file in the logs directory, along with a default logger that will log anything above an info message.

Start Logging

Once that's done, start logging!
ILog logger = log4net.LogManager.GetLogger("Logger");
logger.Info("Testing logging");

Bonus: NHibernate

NHibernate has built in support for log4net which can be really helpful when trying to debug issues.

To enable logging for NHibernate, all you need to do is add the following loggers to the log4net.config file:






Alter the level value to change how much detail you get. Info will get you a lot of detail on queries being run, whilst Warn or Error will limit output to just those messages that are fired off when things are going wrong.

*Update*

I've just been bashing my head against the wall trying to get some logging out of NHibernate, whilst not actually logging anything else.

It seems that because I wasn't instantiating a logger anywhere in code, this was preventing anything being logged by NHibernate.

All I ended up doing was placing the following in my MVCApplication class:
private static ILog logger = log4net.LogManager.GetLogger("default");

*Another Update*

Just for my own sanity so that I don't forget again, you will also need to give write access to the log folder for the user that will be writing there. In the case of ASP .Net MVC, this will be the user setup in the app pool, which is usually something like "IIS AppPool\DefaultAppPool" or "IIS AppPool\ASP.Net v4.0".

Visual Inheritance With .NET Compact Framework

The idea

Recently I've been working on an MVC framework for the .Net compact framework, partly to aid the re-use of certain visual components, such as signature capture screens etc.

As visual inheritance has been supported for the compact framework from VS2005 this should make it very easy to provide a nice base implementation that can then be customised as required.

To this end I created a simple base frame to handle some common functionality and a number of input frames to handle different tasks.

The Problem

At this point the input frames had text overlaid on them in design mode:

Visual inheritance is currently disabled because the base class references a device-specific component or contains p/invoke

Annoying, as I wanted the design time support of being able to visually edit the frames as required.

The Solution

Initial research turned up an MSDN article that discussed this issue and mentioned a number of causes including P/Invokes and device specific code.

The article also states:

If you are sure that platform invoke will not be executed during design time, you can safely enable visual inheritance by putting a DesktopCompatible(true) attribute on the parent form or the parent user control.

This attribute can be applied in a DesignTimeAttributes.xmta file (added through the add file to solution dialog):



true

And...it still failed. 10 more minutes off hair pulling and I realised that fraLogin inherited from BaseFrame, so I added the attribute to that class too:


true

And now visual inhertance works!

Summary

So in short, if you want visual inheritance when developing with the compact framework, remember to add the DesktopCompatible attribute to any controls that will be derived from.

Visual Studio 2003 And Find In Files Under Vista

It's probably widely known by now that Microsoft do not support Visual Studio 2003 under Windows Vista (and 7).

I still have to support a legacy application that was produced with VS2003, so decided to give it a go anyway. To my surprise everthing in the winforms application that I needed basically worked, including debugging, intellsense and so on.

Everything that is until I tried to use 'Find in Files', which promptly crashed Visual Studio.

The Fix

Until that happened, I didn't realise that I use this feature so much, but there is a relatively straight forward fix; by editing the compatibility settings of Visual Studio 2003 and adjusting the following:

  • Run program in compatibility mode for XP SP2
  • Disable Visual Themes
  • Disable Desktop Composition

Alternatively you could go use Visual Basic 6, which is supported by Microsoft under Vista.

XML Deserialization InvalidOperationException

Just a quick one today...

I was asked to help debug an issue with XMLSerialization in .Net where the object graph would serialize fine, but on being deserialized a InvalidOperationException was being thrown.

The class that caused the problem was defined in the following way:


public Class MyClass
{
public int MyInt { get; set; }
public DateTime MyDateTime { get; set; }

public MyClass(DateTime aDateTime)
{
MyDateTime = aDateTime;
}
}

This was nested inside another class in a collection, which initially I thought could be something to do with the problem. It turned out however that in order for deserialization from XML to work, each class that is to be deserialized must have a default constructor so that an instance of the class can be created by the XML deserializer.

This is easy to forget as the C# compiler implicitly adds a default constructor when there are no constructors in a class, but as soon as you add a non-default constructor, this goes away.

Simply adding


public MyClass(){}

Was enough to solve the problem.

The binary formatter does not suffer from this problem, although classes must be marked with the [Serializable] attribute.

ASP .Net Sessions And The Idle Worker Timeout

I've been dealing with the realm of an ASP .Net application recently, and one of the requirements was that the session state should last for up to 60 minutes, which sounded straight forward enough, just whack the following in web.config:





Which works fine in theory, however after leaving the site idle for 20 minutes, the session state suddenly goes away.

After much hair pulling, I finally stumbled accross the Idle Process setting in IIS under the Application Pool configured for the website.

By default this is set to 20 minutes, and as the default Session State is in-process, it gets wiped when the worker process is recycled. On a deployed website this probably wouldn't be an issue as regular requests will keep the process alive, however in a single user testing environment this can obviously cause a problem when trying to test a session timeout greater than 20 minutes.

So there are two solutions to this:
1) Increase the Idle Process timeout setting
2) Use an out of process Session State (StateServer or SQLServer)

The second option simply requires that anything stored in the state be serialisable, and that you enable the ASP .Net StateServer process, although there is a slight cost as the objects have to be serialised and deserialised for each request.

For now I've simply increased the Idle Process timeout setting, however it's definately worth looking at using an out of process Session State as the Worker Process will still be restarted occasionally (Although also configurable) to ensure the health of the web server.

Not sure I totally agree with the approach of reliability through restarts, but I guess it's at least somewhat foolproof.

Concise Invoking into the UI Thread

It's a new year (and has been for a while), so time to get on and actually make use of this blog.

I often find myself having to Invoke execution back in to the UI thread, and thus far the most concise way I have come accross for doing this is as follows:

public void UIFunction(string aMessage)
{
MethodInvoker del = delegate{
lblUILabel.Text = aMessage;
};
Invoke(del);
}

This is nice as it gives you access to the function parameters inside the Invoked anonymous delegate without needing to add them to the invoke call, and also saves you from creating any more functions, whose only purpose is to deal with being invoked.

Obviously you may want to consider that anyway if the logic is complex, but I like that this method keeps things nicely encapsulated in a single function.

The MethodInvoker delegate comes from the Windows.Forms namespace, so if you want to use this method where it is unavailable, such as on the Compact Framework, simply create a new delegate type as follows:
public Delegate void MethodInvoker();