Archive

The full source code for this blog post is available for download.

One of the most interesting features of PostSharp that sets it apart from other AOP tools is its ability to apply aspects at compile-time. As I've explored in previous blog posts, this gives you the ability to do compile time checking and initialization, insteaad of costly and error prone runtime validation. For instance, one could use CompileTimeValidate to enforce that a given aspect can only be used on MVC Controller methods.

    [Serializable]
    public class ConstrainedAspect : OnMethodBoundaryAspect
    {
        public override bool CompileTimeValidate(System.Reflection.MethodBase method)
        {
            if(!method.DeclaringType.IsSubclassOf(typeof(Controller)))
            {
                Message.Write(MessageLocation.Of(method),
				SeverityType.Error,
				"987",
				"Aspect can only be used on Controllers. " + 
				"You applied it on type {0}",
				method.DeclaringType.Name);
                return false;
            }
            return true;
        }

        public override void OnEntry(MethodExecutionArgs args)
        {
            var controller = (Controller) args.Instance;
            controller.ViewData["aspect"] =
			"Constrained Aspect was here at " + DateTime.Now;
        }
    }

This nifty feature has led some Postsharp users to create "aspects" that only contain compile time validation. An architect could put some code in here that helps to validate and enforce the architectural design: an "architectural unit test", if you will. With PostSharp 2.1, these "constraints" become a first-class feature.

There are two types of constraints available in PostSharp 2.1: scalar constraints and referential constraints. The separation is partially a semantic one, as both types of constraints are just ways of enforcing rules at compile time that the C# compiler itself doesn't give you. It's also a technical separation, as referential constraints are checked on all assemblies that reference the code element. (Note that you'll need to turn on architectural validation in the "PostSharp" tab of your project properties, and that this feature is available only in the professional version).

Scalar Constraints

A scalar constraint is a simple constraint that is meant to affect a single piece of code in isolation. This is the most like using a CompileTimeValidation method in an aspect, except without the aspect part. For instance, if you are a user of NHibernate, you know that your entity classes must have virtual properties. However, if you're like me, you might add a new property and forget to make it virtual. Then, you compile your project, run it, go through a test case, and get a runtime error. Wasted time! Here's a scalar constraint that you can apply to your entities to make sure you don't forget.

    [Serializable]
    [MulticastAttributeUsage(MulticastTargets.Class)]
    public class NHEntityAttribute : MulticastAttribute, IScalarConstraint
    {
        public void ValidateCode(object target)
        {
            var targetType = (Type)target;
            var properties = targetType.GetProperties(
			BindingFlags.Public | BindingFlags.Instance);
            var virtualProperties = properties.Where(p => !p.GetGetMethod().IsVirtual);
            foreach (var propertyInfo in virtualProperties)
            {
                Message.Write(MessageLocation.Of(targetType),
				SeverityType.Error,
				"998",
				"Property {0} in Entity class {1} is not virtual",
				propertyInfo.Name, targetType.FullName);
            }
        }

        public bool ValidateConstraint(object target)
        {
            return true;
        }
    }

Note that ValidateConstraint exists to validate the application of the constraint itself (a validation of a validation!). In my example above, I'm performing no validation at all and just returning true, but certainly you could check to make sure this validation is not applied to a static class, for instance. If ValidateConstraint method returns false, then the constraint is considered not valid, and will not be applied.

If you have all your entities in a single namespace, it's very easy to apply this constraint to all your entities (even ones that you haven't written yet) by multicasting that attribute. (For more info on multicasting, check out Dustin's excellent blog posts on multicasting: part 1 and part 2).

[assembly: NHEntity(AttributeTargetTypes = "YourNamespace.Models.Entities")]

When you forget the 'virtual' after you add a new property, you'll see something like this when you compile:

NHEntity compiler error

You could use constraints like this for similar situations, like WCF DataMembers in a DataContract or OperatingContracts in a ServiceContract. You can avoid a lot of frustration and wasted time.

Referential Constraints

Referential constraints are meant to enforce architectural design across assemblies, references, and relationships. This feature can be very useful, especially if you are writing an API. PostSharp actually ships with 3 out-of-the-box constraints for common scenarios: ComponentInternal, InternalImplements, and Internal.

ComponentInternal raises a compiler error if the code its applied to is used in a namespaces besides the one it resides in. For instance:

	// NamespaceA
	namespace PostsharpArchitecturalConstraints.API.NamespaceA
	{
		[ComponentInternal(Severity = SeverityType.Error)]
		internal class ApiA
		{
			public string GetFriendsName()
			{
				return "Mr. Friendly";
			}
		}
	}
	
	// NamespaceB
	using PostsharpArchitecturalConstraints.API.NamespaceA;
	namespace PostsharpArchitecturalConstraints.API.NamespaceB
	{
		public class ApiB
		{
			public string GetFriendsName()
			{
				var a = new ApiA();
				return a.GetFriendsName();
			}
		}
	}

Component Internal compiler error

If you want to specify some exceptions (a specific namespace that you want the internal class to be used in), you can do that in the ComponentInternal's constructor, but by default, it only allows code within its own namespace (and child namespaces) to call it.

InternalImplements is for use on interfaces, and limits implementations of the interface to its own assembly. This means the interface can stay public, for instance, but nothing outside the assembly can implement it.

	// in PostsharpArchitecturalConstraints.API assembly
	namespace PostsharpArchitecturalConstraints.API.Interface
	{
		[InternalImplement(Severity = SeverityType.Error)]
		public interface IPublicInterface
		{
			void DoOperation();
			string GetValue();
		}
	}

	// in PostsharpArchitecturalConstraints assembly
	using PostsharpArchitecturalConstraints.API.Interface;

	namespace PostsharpArchitecturalConstraints.Models.Services
	{
		public class MyPublicInterfaceImpl : IPublicInterface
		{
			private string _value;

			public void DoOperation()
			{
				_value = "operation complete";
			}

			public string GetValue()
			{
				return _value;
			}
		}
	}

InternalImplement compiler error

Why would you want to do this? If you are designing an API, you may want the user to be able to reference an interface, and use your provided implementations of that interface, but you also may want to change your interface somewhere down the line. But, if you make changes to your interface, you could potentially break any implementations that the user has already made. By using InternalImplement, the user retains some flexibility in how they consume your API without the potential of their code breaking when they upgrade to your new version.

And finally, Internal. If you put Internal on a public item, it will remain public, but cannot be used by another assembly.

	// in one assembly
	[Internal]
	public class PublicAndInternal
	{
		public string GetValue()
		{
			return "this can only be called in its own assembly";
		}
	}

	// in another assembly
	public class TryingToUseInternal
	{
		public string Execute()
		{
			var publicInternal = new PublicAndInternal();
			return publicInternal.GetValue();
		}
	}

Internal compiler error

Of course, the door is wide open for you to write your own referential constraints. Here's one I wrote called Unsealable. It makes any classes inherited from the selected class unable to be sealed.

    [MulticastAttributeUsage(MulticastTargets.Class)]
    public class Unsealable : ReferentialConstraint
    {
        public override void ValidateCode(object target,
			System.Runtime.InteropServices._Assembly assembly)
        {
            var targetType = (Type) target;
            var sealedSubClasses = ReflectionSearch.GetDerivedTypes(targetType)
                                        .Where(t => t.DerivedType.IsSealed)
                                        .Select(t => t.DerivedType)
                                        .ToList();
            sealedSubClasses.ForEach(sealedSubClass => Message.Write(
				MessageLocation.Of(sealedSubClass), 
				SeverityType.Error,
				"997",
				"Error on {0}: subclasses of {1} cannot be sealed.",
				sealedSubClass.FullName, targetType.FullName));
        }
    }

This example also makes use of the handy ReflectionSearch utility that comes with PostSharp, which makes certain reflection tasks (like finding derived types in the above example) cleaner, easier, and Linq-ready. Here's an example of applying that constraint:

	[Unsealable]
	public class MyUnsealableClass
	{
		protected string _value;

		public MyUnsealableClass()
		{
			_value = "I'm unsealable!";
		}

		public string GetValue()
		{
			return _value;
		}
	}

	public sealed class TryingToSeal : MyUnsealableClass
	{
		public TryingToSeal()
		{
			_value = "I'm sealed!";
		}
	}

Unsealable error

Constraints can be very valuable for larger teams, or for building an API that will be consumed by a larger audience (even an internal one). Don't go too crazy, though. Only build constraints that will help you, your team, and your API consumers save time and make less mistakes. By enforcing constraints on how code is to be used, you can protect yourself and your users from costly breaking changes down the road. It may be a politically sensitive issue, so good communication is still important, but it's very much like defensive programming, just at the architectual design level.

With prior versions of PostSharp, you had to be very careful to make your software compatible with any obfuscator. You could not obfuscate aspect classes, you could not store reflection objects, and you could not add use a reflection object in RuntimeInitialize with obfuscated generic methods. Indeed, all these features caused PostSharp to store the name of the metadata objects at build time, and to deserialize it at run time. But since the obfuscator renamed metadata objects after build time, the deserialization failed. Briefly said, previous versions of PostSharp were incompatible with all obfuscators.

PostSharp 2,1 provides a mechanism through which assemblies can be “repaired” after they have been obfuscated. Assemblies are still fully obfuscated, but PostSharp provides a utility to repair the name-object table. The build process is the following:

1. The compiler produces an assembly.

2. PostSharp post-processes the assembly and embeds an name table in the output assembly.

3. The obfuscator renames metadata objects, therefore breaks the PostSharp name table.

4. The post-obfuscation step (implemented by PostSharp) repairs the name table based on the obfuscation map produced by the obfuscator, and mapping the old name to the new name.

Since the post-obfuscation utility works with the obfuscation map, we need one implementation of this utility for every obfuscation map format, therefore for every obfuscation tool. PostSharp 2.1 includes support for Dotfuscator, the leading obfuscator .NET.

Calling the post-obfuscator

Let’s see how it works practically. You can download the example and try yourself.

To call the post-obfuscation step, you have to create an MSBuild project file and import the targets AddIns\PostSharp.AddIn.PostObfuscation.targets.

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">

  <ItemGroup>
    <!-- Required: Path of dependencies of obfuscated assemblies. -->
    <ObfuscatedSearchPath Include="Dotfuscated" />
    <!-- Required: Path of dependencies of unobfuscated assemblies. -->
    <UnobfuscatedSearchPath Include="Unobfuscated"/>
    <!-- Required: Obfuscation map file produced by Dotfuscator. -->
    <MapFile Include="Dotfuscated\Map.xml"/>
    <!-- Required: Obfuscated files -->
    <ObfuscatedAssembly Include="Dotfuscated\*.dll"/>
    <ObfuscatedAssembly Include="Dotfuscated\*.exe"/>
    <!-- Optional -->
    <ContentFiles Include="Unobfuscated\*.config"/>
  </ItemGroup>

  <PropertyGroup>
    <!-- Required: output directory -->
    <OutputPath>$(MSBuildProjectDirectory)\Remapped</OutputPath>
    <!-- Required: selection of the remapping strategy -->
    <Obfuscator>Dotfuscator</Obfuscator>
  </PropertyGroup>


  <Target Name="Build" DependsOnTargets="PostObfuscationRemap">
    <!-- Optional: copy other files to the output directory-->
    <Copy SourceFiles="@(ContentFiles)" DestinationFolder="$(OutputPath)"/>
  </Target>

  <Target Name="Rebuild" DependsOnTargets="Clean;Build">
  </Target>
  
  <Import Project="..\..\Build\bin\AddIns\PostSharp.AddIn.PostObfuscation.targets" />
</Project>

 

As you can see, this file defines some locations (required items and properties), and calls the PostObfuscationRemap target defined in PostSharp.AddIn.PostObfuscation.targets.

Safe code references

The post-obfuscator ensures the following references to code are repaired after obfuscation:

  • References you are not aware of (used by PostSharp to provide the runtime features).
  • Reflection objects (for instance MethodInfo, Type) serialized inside objects using the default serializer (BinaryFormatter). This feature is implemented thanks to serialization surrogates for reflection objects.

There is no magic. Other strings referencing to a metadata element, and stored somewhere else than in a reflection object serialized by the default serializer, will not be fixed. If you wrote your custom aspect serializer and want to take advantage of metadata reference serialization, you have to play with IMetadataEmitter/IMetadataDispenser.

In other words, if you want to write obfuscation-safe aspects, the only serialized metadata references should be reflection objects in an aspect field (or somewhere under an aspect field).

Stripping of events and properties

Dotfuscator allows users to remove events and properties from code. The reason is simple: they are useless at runtime for the CLR. They are pure compiler syntactic sugar… or rather were, before XAML. So what if your aspect stores a PropertyInfo or EventInfo?

PostSharp will be smart enough to provide you with a PropertyInfo or EventInfo. The only visible difference is that the Name property will return null. Other properties and methods will work as usually. Under the hood, PostSharp will give you an object of type ObfuscatedPropertyInfo or ObfuscatedEventInfo instead of RuntimePropertyInfo or RuntimeEventInfo, but your code should not see the difference.

Support for other obfuscators

As a first step, we provide support for Dotfuscator. If other vendors are interested to support PostSharp, we’ll gladly provide them with the specification of the binary format. If you want to contribute a post-obfuscation filter, then be pleased that the Dotfuscator-specific code is only 56 lines long (parsing of their XML obfuscation map). The post-obfuscation add-in is not obfuscated so feel free to use a decompiler :).

Summary

That’s it for obfuscation. A small, unexciting feature, but people who need to obfuscate their applications don’t have any excuse not to use PostSharp!

Happy PostSharping!

In my previous post, I introduced the new class ReflectionSearch and two of its methods: GetCustomAttributesOfType and GetCustomAttributesOnTarget. These methods give access to PostSharp’s internal repository of custom attributes.

Today, I would like to cover the second feature of ReflectionSearch: querying the relationships between elements of code. Three kinds of relationships are supported:

  • type inheritance (classes and interfaces),
  • usage in statements (a type, method, or field is used inside a method body),
  • member type,
  • any of the above, but as a type element (described below).

Navigating Type Inheritance

The system reflection API makes it easy to navigate from a child class to its parents, but the opposite is not true: if you want to retrieve all classes implementing a given interface in the assembly, you have to enumerate all types in this assembly, then enumerate all implemented interfaces, and do a recursion on the parent type. As was the case in the previous post with custom attributes, PostSharp indexes the type hierarchy for internal use. From PostSharp 2.1, ReflectionSearch exposes this feature to high-level aspects, and it comes with no performance cost.

The method ReflectionSearch.GetDerivedTypes does what it says, with one remark: by default, it returns only first-level derived types, i.e. it does not return derived types of derived types. If you want a deep search, you have to specify the option ReflectionSearchOptions.IncludeDerivedTypes.

Note that the method does not return an array of types, but of TypeInheritanceCodeReference. This object provides information about the base type. You may think the base type is always what you passed in the argument, but it isn’t always true. Consider the following code:

class GenericCollection<T> : ICollection<T> {}

class IntCollection : GenericCollection<int> {}

TypeInheritanceCodeReference[] derivedTypes = 
ReflectionSearch.GetDerivedTypes( typeof(ICollection<>);

 

In this case, GetDerivedTypes would return two pairs: (GenericCollection<T>, ICollection<T>) and (IntCollection, ICollection<int>). In each case, the base type is a different instance of the generic type.

Navigating Usage

As a part of the post-compilation process, PostSharp scans all method bodies and builds a bi-directional map of using/used-by relationships, i.e. it determines which fields, methods or type are used in statements and expressions of a method body, and creates an index. This functionality is now available inside PostSharp.dll and is exposed on two methods:

  • ReflectionSearch.GetDeclarationsUsedByMethod returns the set of fields, methods and types used by a given method.
  • ReflectionSearch.GetMethodsUsingDeclaration returns all methods using a given field, method, or type.

As you can note, it is not possible to query references to properties and events. Indeed, properties and events are compiler “syntactic sugar” and are never referred to by instructions at MSIL level. If you want to query properties or events, you have to query each accessor separately (add, remove, get, set).

These methods return an array of MethodUsageCodeReference. This object contains both ends of the relationship, as well as a bit mask telling which instructions the declaration was used with – so you can distinguish between a get or a set operation on a field.

Navigating Member Types

The last thing you can do with ReflectionSearch is to get a list of all members of a given type. By member, I mean a field, a property, an event, a parameter, or a return-value parameter.

This feature is exposed on ReflectionsSearch.GetMembersOfType.

Note that PostSharp does not use this feature internally, so there is an additional performance cost in calling that method. The first time you invoke GetMembersOfType, the assembly will be scanned and indexed (using PostSharp’s internal APIes, not System.Reflection).

Type Elements

By default, all methods of ReflectionSearch match the exact type passed as an argument (or match derived types if ReflectionSearchOptions.IncludeDerivedTypes is specified). However, there are cases where you want a larger choice.

Consider the following code:

class Bar {}

class Foo : ICollection<Bar>
{
   Bar[] array;

   void ICollection<Bar> FooBar()
   {
     return new List<Bar>();
   }
}

var derivedTypes = ReflectionSearch.GetDerivedTypes( typeof(Bar), options );
var members = ReflectionSearch.GetMembersOfType( typeof(Bar), options );
var usages = ReflectionSearch.GetMethodsUsingDeclaration( typeof(Bar), options );

 

With the default value of options, the three methods return an empty set. Indeed, there is no type derived from Bar, no field or return value of type Bar, and no instruction using Bar. However, if you include the option ReflectionSearchOptions.IncludeTypeElement, you will get:

  • as derived type: Foo,
  • as members: the field array and the return value of FooBar, and
  • as usages: the method FooBar.

The IncludeTypeElement option asks PostSharp to index at a much deeper level. Pay attention: this comes at a performance cost. PostSharp does not use this feature internally, so the first time you use the option, it will have to scan all type signatures and build an index.

Summary

The new ReflectionSearch class allows you to make complex queries over System.Reflection. Most of the times, the features are already used internally by PostSharp, so they come at minimal performance cost.

The ReflectionSearch class is accessible at build time only. The primary use case is to write more powerful logic for IAspectProvider or MethodPointcut. The second use case is to validate your code. And this is for another blog post.

Happy PostSharping!

-gael