问题
I'm writing a metadata extractor for C# projects. It works by creating SyntaxTrees
from source files via CSharpSyntaxTree.ParseText()
, compiling them via CSharpCompilation.Create()
and then analyzing symbols in the SemanticModel
.
I'm running into an issue where various assembly references aren't being handled correctly.
I generate assembly references by parsing project.assets.json
and extracting the compile-time package references (my test project doesn't include any project references). The targets section of project.assets.json
looks like this:
"targets": {
".NETStandard,Version=v2.1": {
"Autofac/5.1.2": {
"type": "package",
"compile": {
"lib/netstandard2.1/Autofac.dll": {}
},
"runtime": {
"lib/netstandard2.1/Autofac.dll": {}
}
},
"Microsoft.NETCore.Platforms/1.1.0": {
"type": "package",
"compile": {
"lib/netstandard1.0/_._": {}
},
"runtime": {
"lib/netstandard1.0/_._": {}
}
},
"Microsoft.NETCore.Targets/1.1.0": {
"type": "package",
"compile": {
"lib/netstandard1.0/_._": {}
},
"runtime": {
"lib/netstandard1.0/_._": {}
}
},
"Serilog/2.9.0": {
"type": "package",
"compile": {
"lib/netstandard2.0/Serilog.dll": {}
},
"runtime": {
"lib/netstandard2.0/Serilog.dll": {}
}
},
"Serilog.Sinks.Console/3.1.1": {
"type": "package",
"dependencies": {
"Serilog": "2.5.0",
"System.Console": "4.3.0"
},
"compile": {
"lib/netstandard1.3/Serilog.Sinks.Console.dll": {}
},
"runtime": {
"lib/netstandard1.3/Serilog.Sinks.Console.dll": {}
}
},
"Serilog.Sinks.File/4.1.0": {
"type": "package",
"dependencies": {
"Serilog": "2.5.0",
"System.IO.FileSystem": "4.0.1",
"System.Text.Encoding.Extensions": "4.0.11",
"System.Threading.Timer": "4.0.1"
},
"compile": {
"lib/netstandard2.0/Serilog.Sinks.File.dll": {}
},
"runtime": {
"lib/netstandard2.0/Serilog.Sinks.File.dll": {}
}
},
"System.Console/4.3.0": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0",
"Microsoft.NETCore.Targets": "1.1.0",
"System.IO": "4.3.0",
"System.Runtime": "4.3.0",
"System.Text.Encoding": "4.3.0"
},
"compile": {
"ref/netstandard1.3/System.Console.dll": {}
}
},
"System.IO/4.3.0": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0",
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0",
"System.Text.Encoding": "4.3.0",
"System.Threading.Tasks": "4.3.0"
},
"compile": {
"ref/netstandard1.5/System.IO.dll": {}
}
},
"System.IO.FileSystem/4.0.1": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.0.1",
"Microsoft.NETCore.Targets": "1.0.1",
"System.IO": "4.1.0",
"System.IO.FileSystem.Primitives": "4.0.1",
"System.Runtime": "4.1.0",
"System.Runtime.Handles": "4.0.1",
"System.Text.Encoding": "4.0.11",
"System.Threading.Tasks": "4.0.11"
},
"compile": {
"ref/netstandard1.3/System.IO.FileSystem.dll": {}
}
},
"System.IO.FileSystem.Primitives/4.0.1": {
"type": "package",
"dependencies": {
"System.Runtime": "4.1.0"
},
"compile": {
"ref/netstandard1.3/System.IO.FileSystem.Primitives.dll": {}
},
"runtime": {
"lib/netstandard1.3/System.IO.FileSystem.Primitives.dll": {}
}
},
"System.Runtime/4.3.0": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0",
"Microsoft.NETCore.Targets": "1.1.0"
},
"compile": {
"ref/netstandard1.5/System.Runtime.dll": {}
}
},
"System.Runtime.Handles/4.0.1": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.0.1",
"Microsoft.NETCore.Targets": "1.0.1",
"System.Runtime": "4.1.0"
},
"compile": {
"ref/netstandard1.3/System.Runtime.Handles.dll": {}
}
},
"System.Text.Encoding/4.3.0": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0",
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
},
"compile": {
"ref/netstandard1.3/System.Text.Encoding.dll": {}
}
},
"System.Text.Encoding.Extensions/4.0.11": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.0.1",
"Microsoft.NETCore.Targets": "1.0.1",
"System.Runtime": "4.1.0",
"System.Text.Encoding": "4.0.11"
},
"compile": {
"ref/netstandard1.3/System.Text.Encoding.Extensions.dll": {}
}
},
"System.Threading.Tasks/4.3.0": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0",
"Microsoft.NETCore.Targets": "1.1.0",
"System.Runtime": "4.3.0"
},
"compile": {
"ref/netstandard1.3/System.Threading.Tasks.dll": {}
}
},
"System.Threading.Timer/4.0.1": {
"type": "package",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.0.1",
"Microsoft.NETCore.Targets": "1.0.1",
"System.Runtime": "4.1.0"
},
"compile": {
"ref/netstandard1.2/System.Threading.Timer.dll": {}
}
}
}
}
The resulting list of references is this:
lib/netstandard2.1/Autofac.dll
lib/netstandard1.0/_._
lib/netstandard1.0/_._
lib/netstandard2.0/Serilog.dll
lib/netstandard1.3/Serilog.Sinks.Console.dll
lib/netstandard2.0/Serilog.Sinks.File.dll
ref/netstandard1.3/System.Console.dll
ref/netstandard1.5/System.IO.dll
ref/netstandard1.3/System.IO.FileSystem.dll
ref/netstandard1.3/System.IO.FileSystem.Primitives.dll
ref/netstandard1.5/System.Runtime.dll
ref/netstandard1.3/System.Runtime.Handles.dll
ref/netstandard1.3/System.Text.Encoding.dll
ref/netstandard1.3/System.Text.Encoding.Extensions.dll
ref/netstandard1.3/System.Threading.Tasks.dll
ref/netstandard1.2/System.Threading.Timer.dll
I ignore the two oddly-formatted netstandard1.0 ones, replacing them with a reference created by MetadataReference.CreateFromFile( Assembly.Load( "netstandard" ).Location ) )
, and resolve the remaining paths against the local nuget repositories, creating references from the dlls.
This mostly works fine...but certain things don't resolve. Here are the diagnostic messages I'm getting after compiling with CSharpCompilation.Create()
:
CS0103 - The name 'Assembly' does not exist in the current context
CS0103 - The name 'Path' does not exist in the current context
CS1069 - The type name 'ApplicationException' could not be found in the namespace 'System'. This type has been forwarded to assembly 'System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' Consider adding a reference to that assembly. SymbolExtractor::AnalyzeProject
CS0103 - The name 'Environment' does not exist in the current context
Interestingly, all these errors relate to one method in a static class in the project I'm trying to compile. I'm not sure if it's relevant but here's the code in question:
public static string DefineLocalAppDataLogPath( string fileStub, string folder = null )
{
fileStub = IsFileNameValid( fileStub ) ? fileStub : "log.txt";
if( string.IsNullOrEmpty( folder ) )
{
var assLoc = Assembly.GetExecutingAssembly().GetType().Assembly.Location;
folder = Path.GetFileNameWithoutExtension( assLoc );
}
DirectoryInfo logDir = null;
if( ( logDir = CreateLogFileDirectory( folder ) ) == null )
{
if( ( logDir = CreateLogFileDirectory( "LogFiles" ) ) == null )
throw new ApplicationException(
$"Couldn't create log file directory {folder} or the backup/default directory 'LogFiles'" );
}
return logDir.FullName;
}
What am I missing about resolving assembly dependencies? Do I need to also include references to the assemblies required at runtime as well?
来源:https://stackoverflow.com/questions/60404294/resolving-assembly-references-in-roslyn