Want to show your appreciation? Please to my charity.

Monday, October 26, 2009

Generating Interface, Typical Implementation and Decorator of Value Objects

Things To Be Generated

In one of design session, we all felt being repeatedly writing interface, implementation and decorator class for simple value objects that we use. Let’s say way have interfaces below:

    public interface IBase
    {
        IPartOne PartOne { get; set; }
        int BaseInt { get; set; }
        string BaseString { get; set; }
    }
 
    public interface IPartOne
    {
        int PartOneInt { get; set; }
        string PartOneString { get; set; }
    }
 
    public interface ISub : IBase
    {
        int SubInt { get; set; }
        string SubString { get; set; }
 
        IPartTwo PartTwo { get; set; }
    }
 
    public interface IPartTwo
    {
        int PartTwoInt { get; set; }
        string PartTwoString { get; set; }
    }

And then we write implementations

    public class Base : IBase
    {
        public IPartOne PartOne { get; set; }
        public int BaseInt { get; set; }
        public string BaseString { get; set; }
    }
 
    public class PartOne : IPartOne
    {
        public int PartOneInt { get; set; }
        public string PartOneString { get; set; }
    }
 
    public class PartTwo : IPartTwo
    {
        public int PartTwoInt { get; set; }
        public string PartTwoString { get; set; }
    }
 
    public class Sub : Base, ISub
    {
        public int SubInt { get; set; }
        public string SubString { get; set; }
        public IPartTwo PartTwo { get; set; }
    }

And then we wrote decorators so that it can be XML serialized:

    public class BaseDeco : IBase
    {
        private readonly IBase _base;
 
        public IBase Base
        {
            get { return _base;}
        }
 
        public BaseDeco() : this(new Base()) 
        {
        }
 
        public BaseDeco(IBase @base)
        {
            _base = @base;
        }
 
        IPartOne IBase.PartOne
        {
            get { return _base.PartOne; }
            set { _base.PartOne = value; }
        }
 
        public PartOneDeco PartOne
        {
            get { return new PartOneDeco(_base.PartOne); }
            set { _base.PartOne = value.One; }
        }
 
        public int BaseInt
        {
            get { return _base.BaseInt; }
            set { _base.BaseInt = value; }
        }
 
        public string BaseString
        {
            get { return _base.BaseString; }
            set { _base.BaseString = value; }
        }
    }
 
    public class PartOneDeco : IPartOne
    {
        private readonly IPartOne _one;
 
        public PartOneDeco() : this(new PartOne())
        {
        }
 
        public PartOneDeco(IPartOne one)
        {
            _one = one;
        }
 
        public int PartOneInt
        {
            get { return _one.PartOneInt; }
            set { _one.PartOneInt = value; }
        }
 
        public string PartOneString
        {
            get { return _one.PartOneString; }
            set { _one.PartOneString = value; }
        }
 
        public IPartOne One
        {
            get { return _one; }
        }
    }
 
    public class SubDeco : BaseDeco, ISub
    {
        private readonly ISub _sub;
 
        public SubDeco() : this(new Sub())
        {
        }
 
        public SubDeco(ISub sub) : base(sub)
        {
            _sub = sub;
        }
 
        public int SubInt
        {
            get { return _sub.SubInt; }
            set { _sub.SubInt = value; }
        }
 
        public string SubString
        {
            get { return _sub.SubString; }
            set { _sub.SubString = value; }
        }
 
        IPartTwo ISub.PartTwo
        {
            get { return _sub.PartTwo; }
            set { _sub.PartTwo = value; }
        }
 
        public PartTwoDeco PartTwo
        {
            get { return new PartTwoDeco(_sub.PartTwo); }
            set { _sub.PartTwo = value.Two; }
        }
    }
 
    public class PartTwoDeco : IPartTwo
    {
        private readonly IPartTwo _two;
 
        public IPartTwo Two
        {
            get { return _two; }
        }
 
        public PartTwoDeco(IPartTwo two)
        {
            _two = two;
        }
 
        public int PartTwoInt
        {
            get { return _two.PartTwoInt; }
            set { _two.PartTwoInt = value; }
        }
 
        public string PartTwoString
        {
            get { return _two.PartTwoString; }
            set { _two.PartTwoString = value; }
        }
    }
I guess you are probably bored reading them. But there is more, we also have another decorator class for track the changes and raise property change events.

Using T4 to Generate Code

Naturally, code generation, be it compile time or runtime, is what we need. I search around to find a few options:

  1. Commercial product like CodeSmith - Haven’t look any yet.
  2. CodeDom - I used CodeDom in my Web Service Code Generator Project. It is powerful but quite complex to use.
  3. T4 (Text Template Transformation Toolkit – This is the one we are going to give it a try today.
  4. Dynamic proxy using Spring.Net or Castle DP - We have already using Spring.Net dynamic proxy to generate the decorators for property change events and change tracking. With some limitations.
  5. Write our own dynamic proxy using Reflection.Emit API. I used that before, it is also complex but maybe an alternative to option 4 to overcome the limitations. I’ll save this for another post.

After spending a few hours on Oleg Sych’s blog, I started to write a template for produce the code I shown above. The core piece is BvoGeneratorTemplate.tt, which is listed in the end of this post. Let’s take a look at what it can do.

To generate IPartOne and its implementations, all I need to is to add a T4 script file PartOne.tt with below content:

<#@ import namespace="System.Collections.Generic" #>
<#@ template language="C#v3.5" hostspecific="True" debug="True" #>
<#@ output extension="generated.cs" #>
<#@ include file="T4Toolbox.tt" #>
<#@ include file="BvoGeneratorTemplate.tt" #>
 
<#
    var template = new BvoGeneratorTemplate{
     Name = "PartTwo",
     Properties = new List<Property>
        {
            new Property{Type = "int", Name = "PartTwoInt"},
            new Property{Type = "string", Name = "PartTwoString"},
        },
    };
    template.Render();
#>

That automatically generates the code below includes the interface, basic implementation and the decorator class for XML serialization.

// <autogenerated>
//   This file was generated from T4 template BvoGeneratorTemplate.tt.
// </autogenerated>
 
 
#pragma warning disable 1591
namespace ClassLibrary1
{
    public interface IPartTwo 
    {
        int PartTwoInt { get; set;  }
        string PartTwoString { get; set;  }
    }
 
    public partial class PartTwo : IPartTwo
    {
        [CoverageExclude]
        public virtual int PartTwoInt { get; set;  }
        [CoverageExclude]
        public virtual string PartTwoString { get; set;  }
    }
}
namespace ClassLibrary1.Xml
{
    [CoverageExclude]
    public class PartTwoDeco : IPartTwo
    {
        private readonly IPartTwo _partTwo;
        
        public PartTwoDeco(IPartTwo @partTwo)
        {
            _partTwo = @partTwo;
        }
        
        public PartTwoDeco() : this(new PartTwo())
        {
        }
        
        public IPartTwo PartTwo
        {
            get { return _partTwo; }
        }
        public int PartTwoInt 
        {
            get { return _partTwo.PartTwoInt; }
            set { _partTwo.PartTwoInt = value; }
        }
        public string PartTwoString 
        {
            get { return _partTwo.PartTwoString; }
            set { _partTwo.PartTwoString = value; }
        }
    }
}
 
#pragma warning restore 1591

Next let’s take a look at a most complex example Sub.tt:

  1. Sub inherits from Base
  2. Has documentations
  3. A read only computed property
  4. Has a property with a type also generated  by us
<#@ import namespace="System.Collections.Generic" #>
<#@ template language="C#v3.5" hostspecific="True" debug="True" #>
<#@ output extension="generated.cs" #>
<#@ include file="T4Toolbox.tt" #>
<#@ include file="BvoGeneratorTemplate.tt" #>
 
<#
    var template = new BvoGeneratorTemplate {
        Name = "Sub",
        Base = "Base",
        Document = @"
<Summary>
Documentation for ISub
</Summary>
",
         Properties = new List<Property>
        {
            new Property{Type = "int", Name = "SubInt", Document = @"
<Summary>
String property in Sub
</Summary>
"},
            new Property{Type = "string", Name = "SubString"},
            new Property{Type = "IPartTwo", Name = "PartTwo", IsBvo = true},
            new Property{Type = "bool", Name = "IsLarge", IsComputed = true, HasSetter = false},
        },
    };
    template.Render();
#>

Below is the generated code and there are a few things worth mentioning.

  1. There is no implementation for property IsLarge in the Sub class. Developer need to add a regular Sub.cs file to complete the partial class.
  2. In the SubDeco, the IsLarge property is marked as XmlIgnore because a computed property shouldn’t be serialized.
  3. Explicit interface implementation is used for property PartTwo with return type of IPartTwo. And a real PartTwo property is added with return type of PartTowDeco. Because XMLSerializer  doesn’t serialize property of interface type.
// <autogenerated>
//   This file was generated from T4 template BvoGeneratorTemplate.tt.
// </autogenerated>
 
 
#pragma warning disable 1591
namespace ClassLibrary1
{
    /// <Summary>
    /// Documentation for ISub
    /// </Summary>
    public interface ISub : IBase 
    {
        /// <Summary>
        /// String property in Sub
        /// </Summary>
        int SubInt { get; set;  }
        string SubString { get; set;  }
        IPartTwo PartTwo { get; set;  }
        bool IsLarge { get;  }
    }
 
    public partial class Sub : Base, ISub
    {
        [CoverageExclude]
        public virtual int SubInt { get; set;  }
        [CoverageExclude]
        public virtual string SubString { get; set;  }
        [CoverageExclude]
        public virtual IPartTwo PartTwo { get; set;  }
    }
}
namespace ClassLibrary1.Xml
{
    [CoverageExclude]
    public class SubDeco : BaseDeco, ISub
    {
        private readonly ISub _sub;
        
        public SubDeco(ISub @sub) : base(@sub)
        {
            _sub = @sub;
        }
        
        public SubDeco() : this(new Sub())
        {
        }
        
        public ISub Sub
        {
            get { return _sub; }
        }
        public int SubInt 
        {
            get { return _sub.SubInt; }
            set { _sub.SubInt = value; }
        }
        public string SubString 
        {
            get { return _sub.SubString; }
            set { _sub.SubString = value; }
        }
        IPartTwo ISub.PartTwo 
        { 
            get { return _sub.PartTwo; }
            set { _sub.PartTwo = value; }
        }
        public PartTwoDeco PartTwo 
        { 
            get { return new PartTwoDeco( _sub.PartTwo); }
            set { _sub.PartTwo = value.PartTwo; }
        }
        [System.Xml.Serialization.XmlIgnore]
        public bool IsLarge 
        {
            get { return _sub.IsLarge; }
        }
    }
}
 
#pragma warning restore 1591

Other Thoughts

I think the biggest issue here is the documentation. Writing it in the tt file as a string is error prone and unproductive. Possible solutions are:

  1. Define everything in an XML file. Better but still hard to write documentations.
  2. Leaving interfaces in regular cs file, let the tt template parse the interface source file and extract the information. Nice but hard to implement.

Both approach requires further investigation. Your thoughts?

The Template

Finally, here is the template that does all the dirty work.

// <autogenerated>
//   This file was generated from T4 template BvoGeneratorTemplate.tt.
// </autogenerated>
<#@ template language="C#v3.5" hostspecific="True" debug="True" #>
<#@ import namespace="System.Collections.Generic" #>
<#+
public class BvoGeneratorTemplate : Template
{
    public IEnumerable<Property> Properties;
    public string Name;
    public string Base;
    public string Document = string.Empty;
 
    public override string TransformText()
    {
#>
#pragma warning disable 1591
namespace ClassLibrary1
{
<#+
        foreach(string line in Document.Split(new []{'\r','\n'}, StringSplitOptions.RemoveEmptyEntries))
        {
#>
    /// <#=line#>
<#+
        }
#>
    public interface I<#=Name#><#=Base==null? "" : " : I" + Base#> 
    {
<#+
        foreach(Property property in Properties)
        {
            foreach(string line in property.Document.Split(new []{'\r','\n'}, StringSplitOptions.RemoveEmptyEntries))
            {
#>
        /// <#=line#>
<#+
            }
#>
        <#=property.Type#> <#=property.Name#> { <#=property.HasGetter ? "get; " : ""#><#=property.HasSetter? "set; " : ""#> }
<#+
        }
#>
    }
 
    public partial class <#=Name#> : <#=Base==null? "" : Base + ", "#>I<#=Name#>
    {
<#+
        foreach(Property property in Properties)
        {
            if(property.IsComputed) continue;
#>
        [CoverageExclude]
        public virtual <#=property.Type#> <#=property.Name#> { <#=property.HasGetter ? "get; " : ""#><#=property.HasSetter? "set; " : ""#> }
<#+
        }
#>
    }
}
<#+
        var pName = Name;
        if(pName.Length>1 && char.IsUpper(pName[0]) && ! char.IsUpper(pName[1]))
        {
            pName = char.ToLower(pName[0]) + pName.Substring(1);
        }
#>
namespace ClassLibrary1.Xml
{
    [CoverageExclude]
    public class <#=Name#>Deco : <#=Base==null? "" : Base + "Deco, "#>I<#=Name#>
    {
        private readonly I<#=Name#> _<#=pName#>;
        
        public <#=Name#>Deco(I<#=Name#> @<#=pName#>)<#=Base==null? "" : " : base(@"+pName+")"#>
        {
            _<#=pName#> = @<#=pName#>;
        }
        
        public <#=Name#>Deco() : this(new <#=Name#>())
        {
        }
        
        public I<#=Name#> <#=Name#>
        {
            get { return _<#=pName#>; }
        }
<#+
        foreach(Property property in Properties)
        {
            if (!property.IsBvo)
            {
                if(property.IsComputed) {
#>
        [System.Xml.Serialization.XmlIgnore]
<#+
                }
#>
        public <#=property.Type#> <#=property.Name#> 
        {
<#+
                if (property.HasGetter) {
#>
            get { return _<#=pName#>.<#=property.Name#>; }
<#+
                }
                if (property.HasSetter) {
#>
            set { _<#=pName#>.<#=property.Name#> = value; }
<#+
                }
#>
        }
<#+
            }
            else
            {
                var type = property.Type;
                if (type.Length>1 && type[0] == 'I' && char.IsUpper(type[1]))
                {
                    type = type.Substring(1);
                }
#>
        <#=property.Type#> I<#=Name#>.<#=property.Name#> 
        { 
            get { return _<#=pName#>.<#=property.Name#>; }
            set { _<#=pName#>.<#=property.Name#> = value; }
        }
        public <#=type#>Deco <#=property.Name#> 
        { 
            get { return new <#=type#>Deco( _<#=pName#>.<#=property.Name#>); }
            set { _<#=pName#>.<#=property.Name#> = value.<#=type#>; }
        }
<#+
            }
        }
#>
    }
}
 
#pragma warning restore 1591
<#+
        return this.GenerationEnvironment.ToString();
    }
}
    public class Property
    {
        public string Name;
        public string Type;
        public bool IsBvo;
        public bool IsComputed;
        public bool HasGetter = true;
        public bool HasSetter = true;
        public string Document = string.Empty;
    }
#>

Friday, October 23, 2009

Extract The Target Object From The Proxy Generated By Spring.Net

In today’s design session, we called for a quick and dirty hack before we can put a strategic solution in place. The hack is to extract the original target from a proxy of said target.

Given an instance of ITestObject, it is expected to be either of type TestObject or a proxy around an instance of TestObject. Either way, we want to get hold of the TestObject. After digging around the Spring.Net’s source code, we found it is possible. Below is the code to achieve this.

/// <summary> 
/// Extract and return the proxy target if <paramref name="o"/> is a 
/// proxy generated by <see cref="ProxyFactory"/>. Otherwise, return 
/// <paramref name="o"/> itself. 
/// </summary> 
/// <typeparam name="T">The expected type of the target object.</typeparam> 
/// <param name="o"> 
/// An instance of <typeparamref name="T"/> or a proxy of it. 
/// </param> 
/// <returns> 
/// The target instance of <paramref name="o"/> if it is a proxy. 
/// Otherwise, <paramref name="o"/> itself. 
/// </returns> 
/// <exception cref="InvalidCastException"> 
/// If <paramref name="o"/> is neither an instance of <typeparamref name="T"/>, 
/// nor a proxy of <typeparamref name="T"/> instance. 
/// </exception> 
private static T ExtractTarget<T>(object o) 
{ 
    AdvisedProxy ap = o as AdvisedProxy; 
    return (T)(ap == null ? o : ap.m_targetSourceWrapper.GetTarget()); 
} 

Bear in mind that this make your code depends on the detail implementation of the Spring.Net ProxyFactory class, which may be changed in future Spring.Net releases. Hence use it with caution.

Here is the test case for ExtractTarget method.

private static T CreateProxy<T>(T target) 
{ 
    ProxyFactory pf = new ProxyFactory(target); 
    pf.AddInterface(typeof(T)); 
    return (T) pf.GetProxy(); 
} 
 
[Test] public void ProxyTargetTest() 
{ 
    ITestObject target = new TestObject(); 
    Assert.AreSame(target, ExtractTarget<TestObject>(target)); 
 
    ITestObject proxy = CreateProxy<ITestObject>(target); 
    Assert.AreSame(target, ExtractTarget<TestObject>(proxy)); 
} 

Monday, October 12, 2009

MLDonkey Internet Explorer Integration

I have recently setup a home NAS, D-Link DNS-323, and setup MLDonkey to run P2P. It worked great except two problems.

a) it uses a lot of RAM so my poor NAS is running at 1.5M free. DNS-323 only has 64M total. The NAS is still serving other functionality fine so I’m leaving the RAM issue aside for now.

b) I cannot find a decent browser integration solution for Internet Explorer.  But I need to get IE integration working because my other family members, who actually use the P2P most, are still mainly IE users. So here we start.

I started by searching the Google for an existing solution. There is a wiki page about Browser Integration for MLDonkey has comprehensive information but the integration solution for IE is described in only one line.

Mlsubmit.reg

This is the first one I tried as it is the only IE solution listed on the wiki. It manually adds an protocol handler by editing registry. The handler actually reforms the URL then uses IE again open the reformed URL with original ed2k URL as the request parameter. It doesn’t work for two reasons:

  1. Username, password handing. Author use http://username:passwod@site:port/ URL to encode authentication information. Somehow it doesn’t work, It may worked before but IE7 and 8 that I have tried. It gave me unknown site error.
  2. Because it passes ed2k URL as is in the parameter, many special characters are not handled properly. So even after I removed the authentication information (I manually entered when IE prompted me later) the MLDonkey core gets a garbled link and errors out.

Sancho

I installed Sancho, this is a must have for MLDonkey IMHO. It gives a full GUI for MLDonkey Core running on any machine, local or remote. It’s quite small and fast; It’s very useful to submit bittorrent files and check status. The piece of information missing from the wiki page is that Sancho also support protocol association (Search “Input links” in FAQ). In Vista, you’ll need to run it as administrator for it to successfully update the registry, otherwise you get no error but nothing happens too.

So now what’s the problem with Sancho? Actually, it is not the Sancho’s problem, but rather, as always, the broken Internet Explorer when it handles international characters. If an URL contains non-ascii characters and encoded, instead passing it as is to the protocol handler, IE decodes it. It would be fine if it decoded correctly, but unfortunately no, it’s URL decoding logic is completely broken all the way up to IE8.

DonkeyInput

Now I reached the dead end on this. OK, if I cannot find one, I’ll write one. Hence born the DonkeyInput. It’s a tiny (21K) windows application written in C#.

image

DonkeyInput can be downloaded here, it needs no installation. The first run of the program will automatically register itself as ed2k protocol handler, you must run it as administrator on Vista for the first time to allow it successfully change the registry.

Now, restart your browser and click on an ed2k link. The windows above should pop up. All you need to do is set the correct options and click OK button.

Note:

  1. be a little patient if you are adding multiple URLs
  2. be a little patient after you click on OK button for it the send the request to MLDonkey Core.