| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The aspect weaver '<WeaverType>' is provided by two different assemblies: '<FirstAssembly>' and '<SecondAssembly>'. This typically happens when two versions of the same aspect library are referenced, for instance through a package and through a project reference. Remove one of the conflicting references. |
Cause
Weaver-based aspects implement their transformations with a low-level weaver built with the Metalama SDK. The aspect class is bound to its weaver by the RequireAspectWeaverAttribute attribute, which gives the full name of the weaver type. Metalama loads the weavers, the classes annotated with [MetalamaPlugIn], from the compile-time code of the current project and of its references, and identifies each weaver by its full type name. See Aspect weavers.
Metalama reports LAMA0077 when two loaded weavers have the same full type name but come from assemblies with different identities, for instance two versions of the same assembly. Metalama then can't know which weaver you mean. This typically happens when the same aspect library reaches the project through two routes, for instance as a NuGet package and through a project reference, or as two packages that depend on different versions of the library. In the message, <WeaverType> is the full name of the weaver type, and <FirstAssembly> and <SecondAssembly> are the full names of the two assemblies.
When the same assembly, with the same identity, is loaded twice, Metalama doesn't report LAMA0077: the two weavers are interchangeable, and Metalama silently keeps one of them.
The diagnostic isn't attached to any location in the source code.
In the following example, the VirtualizeWeaver weaver is defined in a referenced project, and the main project defines a second weaver with the same full name. Because the two come from different assemblies, Metalama reports LAMA0077.
1using Metalama.Framework.Engine;
2using Metalama.Framework.Engine.AspectWeavers;
3using System.Threading.Tasks;
4
5namespace Doc.LAMA0077.Error;
6
7// Error: this project defines a second weaver with the same full name as the weaver of the referenced project.
8// The #if directive keeps this sample compilable as plain C#, where both files share one assembly.
9[MetalamaPlugIn]
10public class VirtualizeWeaver : IAspectWeaver
11{
12 public Task TransformAsync( AspectWeaverContext context ) => Task.CompletedTask;
13}
14
15[Virtualize]
16internal class Calculator
17{
18 public int Add( int a, int b ) => a + b;
19}
20
using Metalama.Framework.Aspects;
using Metalama.Framework.Engine;
using Metalama.Framework.Engine.AspectWeavers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Threading.Tasks;
namespace Doc.LAMA0077.Error;
// A low-level aspect, which requires the weaver VirtualizeWeaver.
[RequireAspectWeaver( "Doc.LAMA0077.Error.VirtualizeWeaver" )]
public class VirtualizeAttribute : TypeAspect { }
[MetalamaPlugIn]
public class VirtualizeWeaver : IAspectWeaver
{
public Task TransformAsync( AspectWeaverContext context )
=> context.RewriteAspectTargetsAsync( new Rewriter() );
private class Rewriter : CSharpSyntaxRewriter
{
public override SyntaxNode VisitMethodDeclaration( MethodDeclarationSyntax node )
=> node.AddModifiers( SyntaxFactory.Token( SyntaxKind.VirtualKeyword ).WithTrailingTrivia( SyntaxFactory.ElasticSpace ) );
}
}Resolution
- Use the two assembly names given in the message to find how each one reaches the project. In Visual Studio, look under the Dependencies node of the project. On the command line, inspect the
project.assets.jsonfile underobj, or a binary build log. - Remove one of the routes, so that a single version of the aspect library is referenced. For instance, remove the
PackageReferenceif the project also references the library's project, or align the versions of the packages that bring the library. - Rebuild the project.
In the following example, the duplicate weaver is removed, so the weaver comes only from the referenced project.
1namespace Doc.LAMA0077.Fixed;
2
3// The duplicate weaver is removed: the weaver comes only from the referenced project.
4[Virtualize]
5internal class Calculator
6{
7 public int Add( int a, int b ) => a + b;
8}
9
1namespace Doc.LAMA0077.Fixed;
2
3// The duplicate weaver is removed: the weaver comes only from the referenced project.
4[Virtualize]
5internal class Calculator
6{
7 public virtual int Add(int a, int b) => a + b;
8}
9
using Metalama.Framework.Aspects;
using Metalama.Framework.Engine;
using Metalama.Framework.Engine.AspectWeavers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Threading.Tasks;
namespace Doc.LAMA0077.Fixed;
// A low-level aspect, which requires the weaver VirtualizeWeaver.
[RequireAspectWeaver( "Doc.LAMA0077.Fixed.VirtualizeWeaver" )]
public class VirtualizeAttribute : TypeAspect { }
[MetalamaPlugIn]
public class VirtualizeWeaver : IAspectWeaver
{
public Task TransformAsync( AspectWeaverContext context )
=> context.RewriteAspectTargetsAsync( new Rewriter() );
private class Rewriter : CSharpSyntaxRewriter
{
public override SyntaxNode VisitMethodDeclaration( MethodDeclarationSyntax node )
=> node.AddModifiers( SyntaxFactory.Token( SyntaxKind.VirtualKeyword ).WithTrailingTrivia( SyntaxFactory.ElasticSpace ) );
}
}