The Inquisitive Coder – Davy Brion's Blog

Trying to walk that thin line between intelligence and ignorance

Creating Sanity Checks

Posted by Davy Brion on May 24th, 2008

Ever been in a situation where you notice that one of the team-members used classes from an assembly that really shouldn’t be used in that part of the code? For instance, accessing the data layer from the presentation layer. It’s not always easy to keep an eye on improper assembly usage. You could keep an eye on the referenced assemblies manually. You could write an FxCop rule that checks for disallowed assembly references. There’s a lot of stuff you can do, but it’ll always be an after-the-facts check. By that time, the ‘illegal’ code is already there.

Wouldn’t it be cool if you could break the compilation whenever a developer tries to build code that has improper assembly usage? Actually, with PostSharp, we can do just that. You can simply create an aspect like this:

    [Serializable]

    [AttributeUsage(AttributeTargets.Assembly)]

    public class SanityCheck : OnMethodInvocationAspect

    {

        public override bool CompileTimeValidate(System.Reflection.MethodBase method)

        {

            var methodName = method.DeclaringType.FullName + "." + method.Name;

 

            var message = new Message(SeverityType.Fatal, "ProhibitedMethodCall", String.Format(

                "Sorry, but we can't allow you to call {0} from the current assembly", methodName),

                "SanityCheck");

            MessageSource.MessageSink.Write(message);

 

            return false;

        }

    }

First of all, we declare that the SanityCheck attribute can only be applied on the assembly level. Notice that we inherit from OnMethodInvocationAspect. This aspect is applied on events, properties, and methods. So basically, whenever you call a property or method or try to hook to an event in an assembly that you’ve applied this attribute to, our SanityCheck aspect will run. Well, actually we won’t get that far. We override the virtual CompileTimeValidate method where we display a message and then we return false. Meaning that this compilation is invalid.

Suppose you’ve used the attribute in the AssemblyInfo.cs file of your presentation layer like this:

[assembly: SanityCheck(AttributeTargetAssemblies = "System.Data")]

If you try to compile the following code:

            DataTable table = new DataTable();

            table.NewRow();

You’ll see the following line in your build output:

EXEC : error ProhibitedMethodCall: Sorry, but we can't allow you to call System.Data.DataTable.NewRow from the current assembly

And most importantly:

========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========

Obviously, this will only cause compile errors when you try to touch the prohibited parts within the assembly where you used the SanityCheck attribute. If you call a method in another assembly that is allowed to touch System.Data, it will not cause a compile error.

3 Responses to “Creating Sanity Checks”

  1. Peter Says:

    This becomes better with SP1 of VS2008.
    With SP1 there will be a project setting to target only the “NET Framework Client Profile”.

  2. Davy Brion Says:

    well ok, that might prevent people from referencing certain .NET Framework assemblies, but i doesn’t prevent people from (for instance) referencing your DAL assembly in your presentation layer

  3. NHibernate and virtual methods/properties - NHibernate blog - NH Forge Says:

    [...] methods to be virtual, this causes run-time errors when i run my tests. Since i'm already using custom compile time checks, i figured i might as well add another one… from now on, i want my compilation to fail if any of [...]

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>