Wednesday, March 7, 2012

Pathetic breaking change between log4net 1.2.10 and 1.2.11

Somewhere around October 2011 a bugfixed version 1.2.11 of log4net has been released. As log4net is around for years, I guess most people like myself did not update it on day zero.

Today I’ve decided to update one of our applications to use the newest version of log4net and immediately bumped into issues.

First, it seems that for some reason they have signed the newest version of log4net 1.2.11 with a different key. If your application uses any external component (a *.dll) relying on 1.2.10 (and I bet you have such components), the new key means that assembly rebinding will not be possible! In other words, the runtime will not be able to pretend that the new log4net 1.2.11 loaded with your module is the same log4net 1.2.10 which is required by one of your external components.

But hey, they have a workaround for this! It seems that they have two different releases. One is signed with the new key and the other with the old key.

Supposedly then, if you download the 1.2.11 signed with the old key and you rebind the 1.2.10 to 1.2.11 it should work.

So how do you rebind? There are two possible approaches.

A static rebind is just a matter of your configuration file.

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
          <assemblyIdentity name="log4net" publicKeyToken="1b44e1d426115821" culture="neutral" />
          <bindingRedirect oldVersion="0.0.0.0-1.2.10.0"
                           newVersion="1.2.11.0"/>
      </dependentAssembly>
  </assemblyBinding>
</runtime>

A dynamic rebind is a matter of the AssemblyResolve event handler:

AppDomain.CurrentDomain.AssemblyResolve += 
  new ResolveEventHandler( CurrentDomain_AssemblyResolve );
 
static Assembly CurrentDomain_AssemblyResolve( 
    object sender, 
    ResolveEventArgs args )
{
    // rebind any log4net to the current log4net 
    // (assuming you have 1.2.11 added to references
    if ( args.Name.IndexOf( "log4net" ) >= 0 )
        return Assembly.Load( "log4net" );
 
    // a fix to handle mscorlib.resources
    if ( args.Name.IndexOf( ".resources" ) >= 0 )
        return null;
 
    return Assembly.Load( args.Name );
}

So now, no matter which approach you take, it should work. And guess what - unfortunately, it doesn’t.

The reason is really unfortunate. It seems that they have changed the signature of the XmlConfigurator.Configure() method between releases! To me it’s unacceptable, it’s against OOP to break backward compatibility at the object contract level between two minor releases.

In 1.2.10 the Configure method returns void.

In 1.2.11 the Configure method returns ICollection.

The exact problem of the rebinding is then

TypeInitializationException: Method not found: 'Void log4net.Config.XmlConfigurator.Configure()'.

and of course the method is not found as someone has decided to change its signature in 1.2.11! In other words then, the external component referencing 1.2.10 calls XmlConfigurator.Configure() and finds the method in 1.2.11 you provide. But since the method’s signature has changed, the type loader raises the exception and definitely should raise it as calling the method with wrong signature could blow up your runtime because of stack issues.

To me it’s a super fail from the log4net team. The release notes mentions this as one of "new features":

http://logging.apache.org/log4net/release/release-notes.html

I guess my migration to 1.2.11 has ended prematurely.

Thursday, February 23, 2012

Simple fluent and recursive tag builder

The goal was to write a simple fluent and recursive tag builder.

Simple – means the implementation should be as short as possible.

Fluent – means a fluent interface

Recursive – means that tags could possibly be nested one inside the other.

The implementation is as follows:

public class TagBuilder
{
    public TagBuilder() { }
 
    public TagBuilder( string TagName, TagBuilder Parent )
    {
        this.tagName = TagName;
        this.parent = Parent;
    }
 
    private string        tagName;
    private TagBuilder    parent;
    private StringBuilder body = new StringBuilder();
    private Dictionary<string, string> _attributes = new Dictionary<string, string>();
 
    public TagBuilder AddContent( string Content )
    {
        body.Append( Content );
        return this;
    }
 
    public TagBuilder AddContentFormat( string Format, params object[] args )
    {
        body.AppendFormat( Format, args );
        return this;
    }
 
    public TagBuilder StartTag( string TagName )
    {
        TagBuilder tag = new TagBuilder( TagName, this );
 
        return tag;
    }
 
    public TagBuilder EndTag()
    {
        parent.AddContent( this.ToString() );
        return parent;
    }
 
    public TagBuilder AddAttribute( string Name, string Value )
    {
        _attributes.Add( Name, Value );
        return this;
    }
 
    public override string ToString()
    {
        StringBuilder tag = new StringBuilder();
 
        // preamble
        if ( !string.IsNullOrEmpty( this.tagName ) )
            tag.AppendFormat( "<{0}", tagName );
 
        if ( _attributes.Count > 0 )
        {
            tag.Append( " " );
            tag.Append( 
                string.Join( " ", 
                    _attributes
                        .Select( 
                            kvp => string.Format( "{0}='{1}'", kvp.Key, kvp.Value ) )
                        .ToArray() ) );
        }
 
        // body/ending
        if ( body.Length > 0 )
        {
            if ( !string.IsNullOrEmpty( this.tagName) || this._attributes.Count > 0 )
                tag.Append( ">" );
            tag.Append( body.ToString() );
            if ( !string.IsNullOrEmpty( this.tagName ) )
                tag.AppendFormat( "</{0}>", this.tagName );
        }
        else
            if ( !string.IsNullOrEmpty( this.tagName ) )
                tag.Append( "/>" );
 
        return tag.ToString();
    }
}

Example usage:

var script = 
 tag.StartTag( "parent" )
     .AddAttribute( "parentproperty1", "true" )
     .AddAttribute( "parentproperty2", "5" )
         .StartTag( "child1")
         .AddAttribute( "childproperty1", "c" )
         .AddContent( "childbody" )
         .EndTag()
         .StartTag( "child2" )
         .AddAttribute( "childproperty2", "c" )
         .AddContent( "childbody" )
         .EndTag()
     .EndTag()
     .StartTag( "script" )
     .AddContent( "$.scriptbody();")
     .EndTag()
     .ToString();

Note that I can nest the hierarchy plus I can have two or more tags one beside the other (siblings). The output of this example call is:

<parent parentproperty1='true' parentproperty2='5'><child1 childproperty1='c'>ch
ildbody</child1><child2 childproperty2='c'>childbody</child2></parent><script>$.
scriptbody();</script>

Feel free to modify the code. An example extension would be to implement indentation.

Thursday, January 19, 2012

Using expression trees to denote models

Let’s have an XML list of people:

<?xml version="1.0" encoding="utf-8" ?>
<people>
    <person GivenName="John" Surname="Smith" Age="30" />
    <person GivenName="Matthew" Surname="Kowalski" Age="35" />
</people>

and an object model of list items:

public class Person
{
    public string GivenName { get; set; }
    public string Surname { get; set; }
    public int    Age { get; set; }
 
    public override string ToString()
    {
        return string.Format( "{0} {1}, {2}", GivenName, Surname, Age );
    }
}

What we can see here is the mismatch between two domains – a strongly typed OO domain and loosely typed text domain. The mismatch can be resolved using different approaches, for example we could build a set of tags over class members to help the XmlSerializer to deal with plain text data. But trying to be as naive as possible we could provide a helper method which, for given XmlNode, would return a typed value of an attribute.

public static class XmlNodeExtensions
 {
     public static T GetNodeAttribute<T>( this XmlNode Node, string AttributeName )
     {
         if ( Node != null )
             return (T)Convert.ChangeType( Node.Attributes[AttributeName].Value, typeof( T ) );
         else
             return default( T );
     }
 }

The conversion of untyped text data to typed class instances require the knowledge of member signatures:

XmlDocument people = new XmlDocument();
people.Load( "people.xml" );
 
foreach ( XmlNode personNode in people.SelectNodes( "//people/person" ) )
{
    Person person = new Person();
 
    person.GivenName = personNode.GetNodeAttribute<string>( "GivenName" );
    person.Surname   = personNode.GetNodeAttribute<string>( "Surname" );
    person.Age       = personNode.GetNodeAttribute<int>( "Age" );
 
    Console.WriteLine( person );
}

Although such naive approach is common, it has obvious disadvantages. Basically we duplicate the model metadata description on both sides of assignments. The mismatch is still there waiting to bite when models change – if names/types change, we’d have to apply manual changes on one/both sides of above assignments. In particular, refering to members using literal names could possibly bite badly as there’s no chance to catch possible mismatch during the compilation.

The intention of this entry is to document another common approach, a one step further than what is presented above. Note once again that each assignment of a form:

person.GivenName = personNode.GetNodeAttribute<string>( "GivenName" );

contains the same information twice – the name and type of of a class member matches the name of XML attribute, however we have to repeat this information on the right side of the assignment.

Let’s then provide a new extension:

public static class XmlNodeExtensions
 {
     public static T GetNodeAttribute<T>( this XmlNode Node, string AttributeName )
     {
         ... unchanged ...
     }
 
     public static TProperty GetNodeAttribute<TProperty>(
          this XmlNode Node,
          Expression<Func<TProperty>> Property )
     {
         if ( Property != null && Property.Body != null )
             if ( Property.Body.NodeType == ExpressionType.MemberAccess )
             {
                 MemberExpression memberExpression = 
                    (MemberExpression)Property.Body;
 
                 if ( !string.IsNullOrEmpty( memberExpression.Member.Name ) )
                     return Node.GetNodeAttribute<TProperty>( 
                                memberExpression.Member.Name );
             }
 
         return default(TProperty);
     }
 }

This time we require an expression denoting model member, rather than a separate information of its name and type. This allows us to rewrite the client code to:

XmlDocument people = new XmlDocument();
 people.Load( "people.xml" );
 
 foreach ( XmlNode personNode in people.SelectNodes( "//people/person" ) )
 {
     Person person = new Person();
 
     person.GivenName = personNode.GetNodeAttribute( () => person.Surname );
     person.Surname   = personNode.GetNodeAttribute( () => person.GivenName );
     person.Age       = personNode.GetNodeAttribute( () => person.Age );
 
     Console.WriteLine( person );
 }

The possibilities of further enhancements are endless and even such simple one is a significant one as possible mismatch between models can now be caught by the compiler.