@@ -26,6 +26,7 @@ public class DotNetComponentDetector : FileComponentDetector, IExperimentalDetec
2626 private readonly IPathUtilityService pathUtilityService ;
2727 private readonly LockFileFormat lockFileFormat = new ( ) ;
2828 private readonly ConcurrentDictionary < string , string ? > sdkVersionCache = [ ] ;
29+ private readonly JsonDocumentOptions jsonDocumentOptions = new ( ) { CommentHandling = JsonCommentHandling . Skip } ;
2930 private string ? sourceDirectory ;
3031 private string ? sourceFileRootDirectory ;
3132
@@ -137,6 +138,12 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID
137138 {
138139 var lockFile = this . lockFileFormat . Read ( processRequest . ComponentStream . Stream , processRequest . ComponentStream . Location ) ;
139140
141+ if ( lockFile . PackageSpec is null )
142+ {
143+ this . Logger . LogWarning ( "Lock file {LockFilePath} does not contain a PackageSpec." , processRequest . ComponentStream . Location ) ;
144+ return ;
145+ }
146+
140147 var projectAssetsDirectory = this . pathUtilityService . GetParentDirectory ( processRequest . ComponentStream . Location ) ;
141148 var projectPath = lockFile . PackageSpec . RestoreMetadata . ProjectPath ;
142149 var projectOutputPath = lockFile . PackageSpec . RestoreMetadata . OutputPath ;
@@ -184,24 +191,31 @@ protected override async Task OnFileFoundAsync(ProcessRequest processRequest, ID
184191
185192 private string ? GetProjectType ( string projectOutputPath , string projectName , CancellationToken cancellationToken )
186193 {
187- if ( this . directoryUtilityService . Exists ( projectOutputPath ) )
194+ if ( this . directoryUtilityService . Exists ( projectOutputPath ) &&
195+ projectName is not null &&
196+ projectName . IndexOfAny ( Path . GetInvalidFileNameChars ( ) ) == - 1 )
188197 {
189- var namePattern = projectName ?? "*" ;
190-
191- // look for the compiled output, first as dll then as exe.
192- var candidates = this . directoryUtilityService . EnumerateFiles ( projectOutputPath , namePattern + ".dll" , SearchOption . AllDirectories )
193- . Concat ( this . directoryUtilityService . EnumerateFiles ( projectOutputPath , namePattern + ".exe" , SearchOption . AllDirectories ) ) ;
194- foreach ( var candidate in candidates )
198+ try
195199 {
196- try
200+ // look for the compiled output, first as dll then as exe.
201+ var candidates = this . directoryUtilityService . EnumerateFiles ( projectOutputPath , projectName + ".dll" , SearchOption . AllDirectories )
202+ . Concat ( this . directoryUtilityService . EnumerateFiles ( projectOutputPath , projectName + ".exe" , SearchOption . AllDirectories ) ) ;
203+ foreach ( var candidate in candidates )
197204 {
198- return this . IsApplication ( candidate ) ? "application" : "library" ;
199- }
200- catch ( Exception e )
201- {
202- this . Logger . LogWarning ( "Failed to open output assembly {AssemblyPath} error {Message}." , candidate , e . Message ) ;
205+ try
206+ {
207+ return this . IsApplication ( candidate ) ? "application" : "library" ;
208+ }
209+ catch ( Exception e )
210+ {
211+ this . Logger . LogWarning ( "Failed to open output assembly {AssemblyPath} error {Message}." , candidate , e . Message ) ;
212+ }
203213 }
204214 }
215+ catch ( IOException e )
216+ {
217+ this . Logger . LogWarning ( "Failed to enumerate output directory {OutputPath} error {Message}." , projectOutputPath , e . Message ) ;
218+ }
205219 }
206220
207221 return null ;
@@ -246,7 +260,7 @@ private bool IsApplication(string assemblyPath)
246260
247261 if ( string . IsNullOrWhiteSpace ( sdkVersion ) )
248262 {
249- var globalJson = await JsonDocument . ParseAsync ( this . fileUtilityService . MakeFileStream ( globalJsonPath ) , cancellationToken : cancellationToken ) ;
263+ var globalJson = await JsonDocument . ParseAsync ( this . fileUtilityService . MakeFileStream ( globalJsonPath ) , cancellationToken : cancellationToken , options : this . jsonDocumentOptions ) . ConfigureAwait ( false ) ;
250264 if ( globalJson . RootElement . TryGetProperty ( "sdk" , out var sdk ) )
251265 {
252266 if ( sdk . TryGetProperty ( "version" , out var version ) )
@@ -256,14 +270,21 @@ private bool IsApplication(string assemblyPath)
256270 }
257271 }
258272
259- var globalJsonComponent = new DetectedComponent ( new DotNetComponent ( sdkVersion ) ) ;
260- var recorder = this . ComponentRecorder . CreateSingleFileComponentRecorder ( globalJsonPath ) ;
261- recorder . RegisterUsage ( globalJsonComponent , isExplicitReferencedDependency : true ) ;
273+ if ( ! string . IsNullOrWhiteSpace ( sdkVersion ) )
274+ {
275+ var globalJsonComponent = new DetectedComponent ( new DotNetComponent ( sdkVersion ) ) ;
276+ var recorder = this . ComponentRecorder . CreateSingleFileComponentRecorder ( globalJsonPath ) ;
277+ recorder . RegisterUsage ( globalJsonComponent , isExplicitReferencedDependency : true ) ;
278+ return sdkVersion ;
279+ }
280+
281+ // global.json may be malformed, or the sdk version may not be specified.
262282 }
263- else if ( projectDirectory . Equals ( this . sourceDirectory , StringComparison . OrdinalIgnoreCase ) ||
264- projectDirectory . Equals ( this . sourceFileRootDirectory , StringComparison . OrdinalIgnoreCase ) ||
265- string . IsNullOrEmpty ( parentDirectory ) ||
266- projectDirectory . Equals ( parentDirectory , StringComparison . OrdinalIgnoreCase ) )
283+
284+ if ( projectDirectory . Equals ( this . sourceDirectory , StringComparison . OrdinalIgnoreCase ) ||
285+ projectDirectory . Equals ( this . sourceFileRootDirectory , StringComparison . OrdinalIgnoreCase ) ||
286+ string . IsNullOrEmpty ( parentDirectory ) ||
287+ projectDirectory . Equals ( parentDirectory , StringComparison . OrdinalIgnoreCase ) )
267288 {
268289 // if we are at the source directory, source file root, or have reached a root directory, run `dotnet --version`
269290 // this could fail if dotnet is not on the path, or if the global.json is malformed
0 commit comments