Develop Robust Applications

Unlike other AOP frameworks that stop at simple cases, PostSharp is engineered to scale well with complex projects and large teams.

One of the reasons why static programming languages are preferred over dynamic languages for enterprise applications is that the build process offers a first validation of the code. The earlier an error is detected, the easier it is to fix.


The same holds true for PostSharp. As a build-time framework, it ensures aspects are used properly, and can even check custom design rules that are unrelated to aspects.

Compile-Time Validation

The purpose of aspect-oriented programming is to provide a better separation of concerns through encapsulation. Just as precondition checking in imperative programming, compile-time validation allows the author of an aspect to check, at build time, that the aspect is used on elements of code that meet certain assumptions. This is the role of the CompileTimeValidate method.


The following code is taken from a caching attribute. It ensures that the aspect is not applied on a method returning a stream, as only immutable data structures can be cached.

public override bool CompileTimeValidate( MethodBase method ) { MethodInfo methodInfo = (MethodInfo) method; if ( typeof(Stream).IsAssignableFrom( methodInfo.ReturnType )) { Message.Write( SeverityType.Error, "CUSTOM01", "Cannot apply the [Cache] aspect to method {0}.{1} because it returns a Stream.", methodInfo.DeclaringType, methodInfo.Name); return false; } return true; }

Robust Aspect Composition

What happens when several aspects are applied to the same method?

PostSharp includes a comprehensive aspect dependency framework to address the following issues:

Issue Example
Ordering To avoid accidental information disclosures, an authorization aspect must be executed before a caching aspect.
Commutativity Two performance instrumentation aspects can run in random order without affecting the program output. The compiler should not emit any warning in this case.
Requirement An aspect changing the text of the status bar must be preceded by an aspect dispatching the method on a background thread.
Conflict A method cannot have two thread dispatching aspects.

PostSharp includes a robust framework for prevention of conflicts between aspects. The framework is based on graph theory and scales to situations where several aspects are written by different teams or vendors.

The following code snippet illustrates how dependencies can be expressed declaratively:

[Serializable] [ProvideAspectRole(StandardRoles.Threading)] [AspectRoleDependency(AspectDependencyAction.Order, AspectDependencyPosition.Before, "UI")] public sealed class BackgroundThreadAttribute : MethodInterceptionAspect { } [Serializable] [ProvideAspectRole("UI")] [AspectTypeDependency(AspectDependencyAction.Require, typeof(BackgroundThreadAttribute))] public sealed class StatusTextAttribute : OnMethodBoundaryAspect { }

Architecture Validation

PostSharp enables you to validate that the code is being used according to the author's intent. These constraints do not necessarily have to be related to aspects. Contraints are materialized as custom attributes and applied to code.

PostSharp provides the following constraints:

Constraint Description
InternalImplement Specifies that an interface is not meant to be implemented in another assembly, and that the interface author reserves the right to add methods without breaking backward compatibility.
ComponentInternal Specifies that a code element should not be used in a different namespace than its own, i.e. it is considered as internal to this namespace.
Internal Specifies that a code element should not be used in another assembly despite the fact that it is public.
Custom Other constraints can be written using the constraint framework and the extended reflection API (see below).

Extended Reflection API

Thanks to the PostSharp.Reflection.ReflectionSearch class, you can make complex queries over System.Reflection, including:

  • Get all custom attributes of a given type.
  • Get all methods using a given method, field, or type.
  • Get all methods, fields or types used by a given method.
  • Get all types derived from a given class or interface.
  • Get all members or parameters of a given type.

The extended reflection API is typically used in conjunction with CompileTimeValidate, IAspectProvider, or architecture validation.