PostSharp's Great Reset: Announcing Project "Caravela", a Roslyn-based aspect framework

by Gael Fraiteur on 25 Jan 2021

Today we’re excited to make a one-in-ten-years announcement: we’re releasing the first public preview of PostSharp “Caravela”, a Roslyn-based framework for code transformation and aspect-oriented programming.

We intend PostSharp “Caravela” to become the successor of the MSIL-based PostSharp Framework and PostSharp SDK.

PostSharp “Caravela” builds on 15 years of experience in code transformation and aspect-oriented programming, but has been designed from scratch for C# 9 and modern development pipelines. It has a radically different approach than PostSharp.

Today, we’re demonstrating two components of PostSharp “Caravela”:

In this blog post:

Caravela.Framework: a high-level aspect framework

Caravela.Framework is a code transformation and aspect-oriented programming based on templates written in pure C#.

These templates make it easy to write code that combines compile-time information (such as names and types of parameters of a method) and run-time information (such as parameter values) in a natural way, without having to learn another language or having to combine C# with some special templating language.

Instead of a thousand words, let’s look at this example:

Example: logging

▶ Try in your browser

Here is the aspect code. It represents the code transformation.

public class LogAttribute : OverrideMethodAspect
{
    public override object Template()
    {
        Console.WriteLine(target.Method.ToDisplayString() + " started.");

        try
        {
            dynamic result = proceed();

            Console.WriteLine(target.Method.ToDisplayString() + " succeeded.");
            return result;
        }
        catch (Exception e)
        {
            Console.WriteLine(target.Method.ToDisplayString() + " failed: " + e.Message);

            throw;
        }
    }
}

Let’s apply the [Log] aspect to the following method:

[Log]
static int Add(int a, int b)
{
    if ( a == 0 ) throw new ArgumentOutOfRangeException(nameof(a));
    return a + b;
}

The following method gets actually compiled instead of your source code:

[Log]
static int Add(int a, int b)
{
    Console.WriteLine("Program.Add(int, int) started.");
    try
    {
        int result;
        if (a == 0)
            throw new ArgumentOutOfRangeException(nameof(a));
        result = a + b;
        Console.WriteLine("Program.Add(int, int) succeeded.");
        return (int)result;
    }
    catch (Exception e)
    {
        Console.WriteLine("Program.Add(int, int) failed: " + e.Message);
        throw;
    }
}

With Caravela, you can see and debug the C# code being actually compiled. For details, see Debugging code with Caravela.

Caravela.Framework.Sdk: hack the compiler

At PostSharp we are not fans of hacking because it turns out to be a hassle to maintain in the long term (and our frameworks are designed to make your code more maintainable), but sometimes there may be good reasons to overcome the limitations of the language.

Caravela.Framework.Sdk offers direct access to Caravela’s underlying code-modifying capabilities through Roslyn-based APIs. Aspect weavers written with Caravela SDK can perform arbitrary transformations of the project and syntax trees being compiled.

Example: CancellationToken

▶ Try in your browser

The next example demonstrates an aspect that adds a CancellationToken to your methods declarations and method calls where it is missing.

Because the code of an SDK-based aspect weaver is naturally more complex and would not easily fit in a blog post, please go to GitHub if you want to see the source code of the aspect weaver.

Here is some example input code:

[AutoCancellationToken]
class C
{
    public static async Task MakeRequests()
    {
        var client = new HttpClient();
        await MakeRequest(client);
    }

    private static async Task MakeRequest(HttpClient client) 
        => await client.GetAsync("https://httpbin.org/delay/1");
}

What actually compiles is this. You can see that the aspect added CancellationToken parameters and arguments as needed.

[AutoCancellationToken]
class C
{
    public static async Task MakeRequests(
      System.Threading.CancellationToken cancellationToken = default)
    {
        var client = new HttpClient();
        await MakeRequest(client, cancellationToken);
    }
 
    private static async Task MakeRequest(HttpClient client,
        System.Threading.CancellationToken cancellationToken = default) 
        => await client.GetAsync("https://httpbin.org/delay/1", cancellationToken);
}

Benefits of PostSharp “Caravela” over PostSharp MSIL

PostSharp “Caravela” was designed from scratch. It is based on best lessons learned from PostSharp MSIL during the last 15 years, and addresses the main obstacles that are now hindering PostSharp MSIL.

You will enjoy the following benefits with Caravela compared to PostSharp:

Benefits of PostSharp “Caravela” over Roslyn source generators

Unlike Roslyn source generators, PostSharp “Caravela”:

Most Anticipated Questions

How long will the MSIL-based PostSharp be maintained?

Our current release plan with the MSIL-based PostSharp is:

PostSharp 6.10 LTS will be our last supported version of the MSIL-based stack and we intend to support it according to our support policies, that is, 1 year after Caravela reaches a first LTS version. We will work with our customers to ensure the smoothest possible transition.

Will PostSharp “Caravela” be compatible with PostSharp 6.*?

How compatible do we intend to be with PostSharp MSIL? How much code will you need to rewrite?

It has been 12 years since the last major breaking change in PostSharp. Do you remember the .NET landscape in 2008? Clearly, we cannot build a new platform by keeping compatibility with designs that were optimal 12 years ago. However, we understand that PostSharp is used by thousands and we want to find a compromise between modernity and backward compatibility.

We have already taken the following compromise:

What will happen with PostSharp Patterns?

We intend to port PostSharp Patterns to PostSharp “Caravela” in a way that maximizes backward compatibility, but we may also take the the opportunity to make a few long-due breaking changes.

How will PostSharp “Caravela” be licensed and priced?

We don’t know yet. The preview releases are being licensed under the terms of the Evaluation License of PostSharp.

Summary

PostSharp “Caravela” is the future of aspect-oriented programming and metaprogramming in .NET. It will take us a long time to get there, but the possibilities are amazing and the path much less rocky than 10 years ago.

For more information, please have a look at the home of PostSharp “Caravela” on GitHub.

If you have any feedback or question regarding Caravela, please open an issue, start a discussion, or contact us directly at hello@postsharp.net.

Comments

newsletter

Subscribe to our
newsletter

Stay up to date on all the latest releases, news and discounts.
Follow us on social media: