At tonight’s meeting of the Wellington .NET User group we had two presentations – one on Linq Syntax from Owen Evans, and one on avoiding Cross Site Scripting attacks from Kirk Jackson. Both presentations were informative and interesting, and I learnt a few new things from each.

Owen’s Linq presentation reminded me of a couple of Linq goodies that I wrote recently – so I thought I’d share.

On one project, we’re using an SOA with the business processes and logic implemented on the server, and a client application providing a rich user experience on each workstation. Flowing between the two, we have a menagerie of Data Transfer Objects, each representing a particular query, result or state change.

For DTOs to work within the WCF framework, they have to be marked with the SerializableAttribute. Leave this off and things won’t work.

Well, wouldn’t you know it, but we had a service that was dying with cryptic errors – which we eventually solved by adding the attribute to the class as required. One of my colleagues was resigned to manually checking every class (there were over 200 at the time, and we have more now), but I figured there had to be a better way.

Combining Linq, Reflection, NUnit and a flash of inspiration, this is where we ended up – with a simple unit test that verifies that all our Data Transfer Objects are properly tagged as serializable:

[Test]
public void EnsureAllDtosAreSerialisable()
{
    var nonSerializable
        = typeof(DataTransferObject).Assembly
            .GetExportedTypes()
            .Where(type => type.IsClass)
            .Where(type => typeof(DataTransferObject)
                .IsAssignableFrom(type))
            .Where(type => type.GetCustomAttributes(
                typeof(SerializableAttribute),
                false).Count() == 0);

    Assert.That(nonSerializable.Count(),
        Is.EqualTo(0),
        nonSerializable.Aggregate("Found ", (a, t) => a + t.Name + "; "));
}

How does this work? Here’s the algorithm in English:

  • From the assembly containing the type DataTransferObject, find all exported types that are classes;

  • that could be assigned to a variable of type DataTrasferObject;

  • where the count of SerializableAttribute attributes is zero.

  • Then, assert that the result of this search is empty – that there are no classes that match. If such classes are found, list them in the error for the Assert.

Elsewhere in the same project, we are using NHibernate as our ORM layer. To support lazy loading, we need to mark our properties and methods as virtual to allow them to be overidden by NHibernates lazy loading proxy classes.

Normally NHibernate is pretty good about complaining when things are not properly marked as virtual, but we found a situation where some properties were only partially virtual – one accessor (normally the public getter) was virtual, but the other (often a protected setter) was not virtual.

Again, Linq to the rescue with a unit test:

[Test]
public void RequirePropertiesToBeCompletelyVirtualOrNot()
{
    var properties
        = typeof(FsisBusinessEntity).Assembly
            .GetExportedTypes()
            .Where(type => type.IsClass)
            .SelectMany(
                type => type.GetProperties(
                    BindingFlags.Instance
                    | BindingFlags.Public 
                    | BindingFlags.NonPublic))
            .Where( property => property.CanRead
                                && property.CanWrite)
            .Where(property => property.GetGetMethod(true).IsVirtual
                               != property.GetSetMethod(true).IsVirtual);

    Assert.That(
        properties.Count(),
        Is.EqualTo(0),
        properties.Aggregate(
            "Found : ",
            (m, p) => m + string.Format("{0}.{1}; ",
                                        p.DeclaringType.Name,
                                        p.Name)));
}

Again, here’s a translation into English to help with readability:

  • From the assembly containing the FsisBusinessEntity class, get all Exported types that are classes;

  • From those exported classes, select all the instance properties (whether public or not) where the property is read/write;

  • and one accessor is marked virtual where the other is not.

  • If there are any properties that satisfy this search, list them in the result of the failed assertion.

This test worked very well – almost all of the properties it identified were real issues that would have bitten us later on. The one remaining property was a bit weird, but asking “Why is this property Getter virtual?” on StackOverflow soon found us the explanation.

Comments

blog comments powered by Disqus