Caravela.Framework.Sdk
Table of contents
- Table of contents
- Introduction
- Maturity
- Implementing an aspect
- Packaging your aspect with its weaver
- Examples
Introduction
Caravela.Framework.Sdk offers direct access to Caravela's underlying code-modifying capabilities through Roslyn-based APIs.
Unlike Caravela.Framework, our high-level API, aspects built with Caravela.Framework.Sdk must be in their own project, separate from the code they transform. Caravela.Framework.Sdk is much more complex and unsafe than Caravela.Framework and is not meant for "everyday" use. We expect that most developers will use Caravela.Framework.
Maturity
Caravela.Framework.Sdk is in preview, but it is mostly feature complete.
Implementing an aspect
Step 1. Define the public interface of your aspect (a custom attribute)
Create an "interface" project (it must target .NET Standard 2.0).
Add a reference to the Caravela.Framework package (but not Caravela.Framework.Sdk).
Define a custom attribute like this:
[AttributeUsage(AttributeTargets.Assembly)] public class VirtuosityAspect : Attribute, IAspect { }
Step 2. Create the weaver for this project
Create a project that targets .NET Standard 2.0 and name it with the
.Weaver
suffix (by convention).Add a reference the Caravela.Framework.Sdk package.
Add a reference to the first project project. In the
<ProjectReference>
in your csproj file, additionally specifyPrivateAssets="all"
.Add a class that implements the following interface:
public interface IAspectWeaver { CSharpCompilation Transform(AspectWeaverContext context); }
where:
public sealed class AspectWeaverContext { public CSharpCompilation Compilation { get; } public IReadOnlyList<AspectInstance> AspectInstances { get; } public IDiagnosticSink Diagnostics { get; } }
An implementation of this interface receives a Roslyn compilation and can modify it in any way using Roslyn syntax and semantic APIs. It also receives information about where its associated attribute has been applied (called "aspect instances"). And it can produce diagnostics (errors and warnings) if it has been used incorrectly.
Note that because Caravela replaces the compiler used to build your code, but not the one used by the IDE, any modifications made here will not affect code completion.
Add these custom attributes to your class:
[CompilerPlugin, AspectWeaver(aspectType: typeof(VirtuosityAspect))]
For instance:
[CompilerPlugin, AspectWeaver(aspectType: typeof(VirtuosityAspect))]
class VirtuosityWeaver : IAspectWeaver
{
public CSharpCompilation Transform(AspectWeaverContext context)
{
// Details skipped.
}
}
Step 3. Use your aspect
In a third project:
Reference the first project (the one defining the custom attribute). Add
OutputItemType="Analyzer" ReferenceOutputAssembly="false"
to its<ProjectReference>
in the csproj file.Reference the second project (the one defining the weaver). Add
OutputItemType="Analyzer"
to its<ProjectReference>
.Reference the Caravela.Framework package.
Use the aspect by applying the attribute:
[assembly: VirtuosityAspect]
Packaging your aspect with its weaver
Packing a weaver project that was created using the steps above will produce a package that contains all parts of the aspect, including its dependencies (simplifying step 3 above), but with a name ending with .Weaver
.
To fix this:
- Specify
<PackageId>
without the.Weaver
suffix inside a<PropertyGroup>
in the csproj of the second project. - Specify
<PackageId>
with a.Redist
suffix inside a<PropertyGroup>
in the csproj of the first project. - (Optional) Add
<IsPackable>false</IsPackable>
to a<PropertyGroup>
in the csproj of the first project, to prevent you from creating a package that would contain just the attribute.
Examples
Available examples of Caravela.Framework.Sdk weavers are:
- Caravela.Open.Virtuosity: makes all possible methods in a project
virtual
- Caravela.Open.AutoCancellationToken: automatically propagates
CancellationToken
parameter - Caravela.Open.DependencyEmbedder: bundles .NET Framework applications into a single executable file
The Caravela.Open.Virtuosity repository contains very little logic, so it can be used as a template for your own weavers.