Open sandboxFocusImprove this doc

Exposing configuration (before 2023.4)

Note

Starting with Metalama 2023.4, this approach is considered obsolete.

To expose a configuration API prior to Metalama 2023.4:

  1. Create a class that inherits from ProjectExtension and includes a default constructor.
  2. If necessary, override the Initialize method, which accepts an IProject.
  3. In your aspect code, call the IProject.Extension method, where T represents your configuration class, to get the configuration object.
  4. Optionally, create an extension method for the IProject type to make your configuration API more discoverable. Annotate the class with [CompileTime].
  5. To configure your aspect, users should implement a project fabric and access your configuration API using this extension method.

Example

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System.Diagnostics;
4
5namespace Doc.AspectConfiguration;
6
7// The aspect itself, consuming the configuration.
8public class LogAttribute : OverrideMethodAspect
9{
10    public override dynamic? OverrideMethod()
11    {
12        var options = meta.Target.Method.Enhancements().GetOptions<LoggingOptions>();
13
14        var message = $"{options.Category}: Executing {meta.Target.Method}.";
15
16        switch ( options.Level!.Value )
17        {
18            case TraceLevel.Error:
19                Trace.TraceError( message );
20
21                break;
22
23            case TraceLevel.Info:
24                Trace.TraceInformation( message );
25
26                break;
27
28            case TraceLevel.Warning:
29                Trace.TraceWarning( message );
30
31                break;
32
33            case TraceLevel.Verbose:
34                Trace.WriteLine( message );
35
36                break;
37        }
38
39        return meta.Proceed();
40    }
41}
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Fabrics;
3using Metalama.Framework.Options;
4using System.Diagnostics;
5using System.Linq;
6
7namespace Doc.AspectConfiguration;
8
9// The project fabric configures the project at compile time.
10public class Fabric : ProjectFabric
11{
12    public override void AmendProject( IProjectAmender amender )
13    {
14        amender.SetOptions(
15            new LoggingOptions { Category = "GeneralCategory", Level = TraceLevel.Info } );
16
17        amender
18            .Select( x => x.GlobalNamespace.GetDescendant(
19                         "Doc.AspectConfiguration.ChildNamespace" )! )
20            .SetOptions( new LoggingOptions() { Category = "ChildCategory" } );
21
22        // Adds the aspect to all members.
23        amender
24            .SelectMany( c => c.Types.SelectMany( t => t.Methods ) )
25            .AddAspectIfEligible<LogAttribute>();
26    }
27}
1using Metalama.Framework.Code;
2using Metalama.Framework.Options;
3using System.Diagnostics;
4
5namespace Doc.AspectConfiguration;
6
7// Options for the [Log] aspects.
8public class LoggingOptions : IHierarchicalOptions<IMethod>, IHierarchicalOptions<INamedType>,
9                              IHierarchicalOptions<INamespace>, IHierarchicalOptions<ICompilation>
10{
11    public string? Category { get; init; }
12
13    public TraceLevel? Level { get; init; }
14
15    object IIncrementalObject.ApplyChanges( object changes, in ApplyChangesContext context )
16    {
17        var other = (LoggingOptions) changes;
18
19        return new LoggingOptions
20        {
21            Category = other.Category ?? this.Category, Level = other.Level ?? this.Level
22        };
23    }
24}
Source Code
1namespace Doc.AspectConfiguration
2{


3    // Some target code.
4    public class SomeClass
5    {
6        [Log]
7        public void SomeMethod() { }
8    }
9



10    namespace ChildNamespace
11    {
12        public class SomeOtherClass
13        {
14            [Log]
15            public void SomeMethod() { }
16        }
17    }



18}
Transformed Code
1using System.Diagnostics;
2
3namespace Doc.AspectConfiguration
4{
5    // Some target code.
6    public class SomeClass
7    {
8        [Log]
9        public void SomeMethod()
10        {
11            Trace.TraceInformation("GeneralCategory: Executing SomeClass.SomeMethod().");
12        }
13    }
14
15    namespace ChildNamespace
16    {
17        public class SomeOtherClass
18        {
19            [Log]
20            public void SomeMethod()
21            {
22                Trace.TraceInformation("ChildCategory: Executing SomeOtherClass.SomeMethod().");
23            }
24        }
25    }
26}