One of the new features in .NET 5 that triggered my curiosity where source generators. I did some investigation on how to use them and want to share the lessons I learned along the way.
Yesterday I got my first source generator finally up and running. Now it is time to move on and do something more interesting. I found an example on Github that created a strongly typed config class based on your appsettings.json. I tried to duplicate the code but when I build my application the source generator didn’t run.
In the build output I noticed the following warning:
Severity | Code | Description | Project | File | Line | Suppression State | Detail Description |
Warning | CS8034 | Unable to load Analyzer assembly c:\lib\netstandard2.0\System.Text.Encodings.Web.dll: Could not find a part of the path 'c:\lib\netstandard2.0\System.Text.Encodings.Web.dll'. | SourceGeneratorsExample | 1 | Active | System.IO.FileNotFoundException: Could not find a part of the path 'c:\lib\netstandard2.0\System.Text.Encodings.Web.dll'.File name: 'c:\lib\netstandard2.0\System.Text.Encodings.Web.dll' ---> System.IO.DirectoryNotFoundException: Could not find a part of the path 'c:\lib\netstandard2.0\System.Text.Encodings.Web.dll'. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) at Roslyn.Utilities.FileUtilities.OpenFileStream(String path) at Roslyn.Utilities.FileUtilities.OpenFileStream(String path) at Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.GetAnalyzerTypeNameMap(String fullPath, AttributePredicate attributePredicate, AttributeLanguagesFunc languagesFunc) at Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.Extensions`1.GetExtensionTypeNameMap() at Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.Extensions`1.AddExtensions(Builder builder)-----System.IO.DirectoryNotFoundException: Could not find a part of the path 'c:\lib\netstandard2.0\System.Text.Encodings.Web.dll'. at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost) at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share) at Roslyn.Utilities.FileUtilities.OpenFileStream(String path)----- |
The source generator is using System.Text.Json and System.Text.Encodings.Web to parse the config files. But it seems that the source generator cannot find and use these references.
How to use external references in source generators?
There is some extra work that needs to be done before external libraries can be loaded successfully.
For every reference that your source generator needs you need to do 2 things:
- Take a private dependency on the package(PrivateAssets=all). By doing this consumers of the generator will not reference it.
- Set the dependency to generate a path property by adding
GeneratePathProperty="true"
. This will create a new MSBuild property of the formatPKG<PackageName>
where<PackageName>
is the package name with.
replaced by_
.
Now we can then use the generated path property to add the binaries to the resulting NuGet package as we do with the generator itself:
More information in the source generators cookbook: https://github.com/dotnet/roslyn/blob/master/docs/features/source-generators.cookbook.md#use-functionality-from-nuget-packages