@@ -206,20 +206,23 @@ public static string DeterminePublishLocation(string workingDirectory, string pr
206206 return path ;
207207 }
208208
209- public static string LookupTargetFrameworkFromProjectFile ( string projectLocation )
209+
210+ // <summary>
211+ /// Looks up specified properties from a project file.
212+ /// </summary>
213+ /// <param name="projectLocation">The location of the project file.</param>
214+ /// <param name="propertyNames">The names of the properties to look up.</param>
215+ /// <returns>A dictionary of property names and their values.</returns>
216+ public static Dictionary < string , string > LookupProjectProperties ( string projectLocation , params string [ ] propertyNames )
210217 {
211218 var projectFile = FindProjectFileInDirectory ( projectLocation ) ;
212- if ( string . IsNullOrEmpty ( projectFile ) )
213- {
214- throw new FileNotFoundException ( "Could not find a project file in the specified directory." ) ;
215- }
216-
217- var arguments = new [ ]
219+ var properties = new Dictionary < string , string > ( ) ;
220+ var arguments = new List < string >
218221 {
219222 "msbuild" ,
220223 projectFile ,
221- "--getProperty:TargetFramework,TargetFrameworks " ,
222- "-nologo "
224+ "-nologo " ,
225+ $ "--getProperty: { string . Join ( ',' , propertyNames ) } "
223226 } ;
224227
225228 var process = new Process
@@ -234,105 +237,94 @@ public static string LookupTargetFrameworkFromProjectFile(string projectLocation
234237 CreateNoWindow = true
235238 }
236239 } ;
237-
238- process . Start ( ) ;
239- string output = process . StandardOutput . ReadToEnd ( ) ;
240- string error = process . StandardError . ReadToEnd ( ) ;
241- process . WaitForExit ( ) ;
242-
243- if ( process . ExitCode != 0 )
244- {
245- throw new Exception ( $ "MSBuild process exited with code { process . ExitCode } . Error: { error } ") ;
246- }
247-
248240 try
249241 {
250- using JsonDocument doc = JsonDocument . Parse ( output ) ;
251- JsonElement root = doc . RootElement ;
252- JsonElement properties = root . GetProperty ( "Properties" ) ;
242+ process . Start ( ) ;
243+ string output = process . StandardOutput . ReadToEnd ( ) ;
244+ string error = process . StandardError . ReadToEnd ( ) ;
245+ process . WaitForExit ( ) ;
253246
254- if ( properties . TryGetProperty ( "TargetFramework" , out JsonElement targetFramework ) )
247+ if ( process . ExitCode == 0 )
255248 {
256- string framework = targetFramework . GetString ( ) ;
257- if ( ! string . IsNullOrEmpty ( framework ) )
249+ using JsonDocument doc = JsonDocument . Parse ( output ) ;
250+ JsonElement root = doc . RootElement ;
251+ JsonElement propertiesElement = root . GetProperty ( "Properties" ) ;
252+
253+ foreach ( var property in propertyNames )
258254 {
259- return framework ;
255+ if ( propertiesElement . TryGetProperty ( property , out JsonElement propertyValue ) )
256+ {
257+ properties [ property ] = propertyValue . GetString ( ) ;
258+ }
260259 }
261260 }
262-
263- if ( properties . TryGetProperty ( "TargetFrameworks" , out JsonElement targetFrameworks ) )
261+ else
264262 {
265- string frameworks = targetFrameworks . GetString ( ) ;
266- if ( ! string . IsNullOrEmpty ( frameworks ) )
267- {
268- return frameworks . Split ( ';' ) [ 0 ] ;
269- }
263+ Console . WriteLine ( $ "MSBuild process exited with code { process . ExitCode } . Error: { error } ") ;
264+ // Fallback to XML parsing
265+ properties = LookupProjectPropertiesFromXml ( projectFile , propertyNames ) ;
270266 }
271267 }
272- catch ( JsonException ex )
268+ catch ( Exception ex )
273269 {
274- throw new Exception ( $ "Failed to parse MSBuild output: { ex . Message } . Output: { output } ") ;
270+ Console . WriteLine ( $ "Error executing MSBuild or parsing output: { ex . Message } ") ;
271+ // Fallback to XML parsing
272+ properties = LookupProjectPropertiesFromXml ( projectFile , propertyNames ) ;
275273 }
276274
277- return null ;
275+ return properties ;
278276 }
279277
280- /// <summary>
281- /// Retrieve the `OutputType` property of a given project
282- /// </summary>
283- /// <param name="projectLocation">Path of the project</param>
284- /// <returns>The value of the `OutputType` property</returns>
285- public static string LookupOutputTypeFromProjectFile ( string projectLocation )
278+ private static Dictionary < string , string > LookupProjectPropertiesFromXml ( string projectFile , string [ ] propertyNames )
286279 {
287- var process = new Process ( ) ;
288- var output = string . Empty ;
289- var msbuildProcessFailed = false ;
280+ var properties = new Dictionary < string , string > ( ) ;
290281 try
291282 {
292- process . StartInfo = new ProcessStartInfo ( )
293- {
294- FileName = "dotnet" ,
295- Arguments = $ "msbuild { projectLocation } -getProperty:OutputType",
296- RedirectStandardOutput = true ,
297- UseShellExecute = false ,
298- WindowStyle = ProcessWindowStyle . Hidden
299- } ;
300-
301- process . Start ( ) ;
302- output = process . StandardOutput . ReadToEnd ( ) ;
303- var hasExited = process . WaitForExit ( 5000 ) ;
304-
305- // If it hasn't completed in the specified timeout, stop the process and give up
306- if ( ! hasExited )
307- {
308- process . Kill ( ) ;
309- msbuildProcessFailed = true ;
310- }
311-
312- // If it has completed but unsuccessfully, give up
313- if ( process . ExitCode != 0 )
283+ var xdoc = XDocument . Load ( projectFile ) ;
284+ foreach ( var propertyName in propertyNames )
314285 {
315- msbuildProcessFailed = true ;
286+ var element = xdoc . XPathSelectElement ( $ "//PropertyGroup/{ propertyName } ") ;
287+ if ( element != null && ! string . IsNullOrWhiteSpace ( element . Value ) )
288+ {
289+ properties [ propertyName ] = element . Value ;
290+ }
316291 }
317292 }
318- catch ( Exception )
293+ catch ( Exception ex )
319294 {
320- // swallow any exceptions related to `dotnet msbuild`
321- msbuildProcessFailed = true ;
295+ Console . WriteLine ( $ "Error parsing project file XML: { ex . Message } ") ;
322296 }
297+ return properties ;
298+ }
323299
324- if ( msbuildProcessFailed )
300+ /// <summary>
301+ /// Looks up the target framework from a project file.
302+ /// </summary>
303+ /// <param name="projectLocation">The location of the project file.</param>
304+ /// <returns>The target framework of the project.</returns>
305+ public static string LookupTargetFrameworkFromProjectFile ( string projectLocation )
306+ {
307+ var properties = LookupProjectProperties ( projectLocation , "TargetFramework" , "TargetFrameworks" ) ;
308+ if ( properties . TryGetValue ( "TargetFramework" , out var targetFramework ) && ! string . IsNullOrEmpty ( targetFramework ) )
325309 {
326- var projectFile = FindProjectFileInDirectory ( projectLocation ) ;
327- var xdoc = XDocument . Load ( projectFile ) ;
328- var element = xdoc . XPathSelectElement ( "//PropertyGroup/OutputType" ) ;
329- output = element ? . Value ;
310+ return targetFramework ;
311+ }
312+ if ( properties . TryGetValue ( "TargetFrameworks" , out var targetFrameworks ) && ! string . IsNullOrEmpty ( targetFrameworks ) )
313+ {
314+ return targetFrameworks . Split ( ';' ) [ 0 ] ;
330315 }
316+ return null ;
317+ }
331318
332- return
333- string . IsNullOrEmpty ( output ) ?
334- null :
335- output . Trim ( ) ;
319+ /// <summary>
320+ /// Retrieve the `OutputType` property of a given project
321+ /// </summary>
322+ /// <param name="projectLocation">Path of the project</param>
323+ /// <returns>The value of the `OutputType` property</returns>
324+ public static string LookupOutputTypeFromProjectFile ( string projectLocation )
325+ {
326+ var properties = LookupProjectProperties ( projectLocation , "OutputType" ) ;
327+ return properties . TryGetValue ( "OutputType" , out var outputType ) ? outputType . Trim ( ) : null ;
336328 }
337329
338330 public static bool LookPublishAotFlag ( string projectLocation , string msBuildParameters )
@@ -350,43 +342,32 @@ public static bool LookPublishAotFlag(string projectLocation, string msBuildPara
350342 }
351343 }
352344
353- // If the property wasn't provided in msBuildParameters, fall back to searching project file
354- var projectFile = FindProjectFileInDirectory ( projectLocation ) ;
355-
356- var xdoc = XDocument . Load ( projectFile ) ;
357-
358- var element = xdoc . XPathSelectElement ( "//PropertyGroup/PublishAot" ) ;
359-
360- if ( bool . TryParse ( element ? . Value , out bool result ) )
345+ var properties = LookupProjectProperties ( projectLocation , "PublishAot" ) ;
346+ if ( properties . TryGetValue ( "PublishAot" , out var publishAot ) )
361347 {
362- return result ;
348+ return bool . TryParse ( publishAot , out var result ) && result ;
363349 }
364-
365350 return false ;
366351 }
352+
353+
367354 public static bool HasExplicitSelfContainedFlag ( string projectLocation , string msBuildParameters )
368355 {
369356 if ( msBuildParameters != null && msBuildParameters . IndexOf ( "--self-contained" , StringComparison . InvariantCultureIgnoreCase ) != - 1 )
370357 {
371358 return true ;
372359 }
373360
374- // If the property wasn't provided in msBuildParameters, fall back to searching project file
375- var projectFile = FindProjectFileInDirectory ( projectLocation ) ;
376-
377- var xdoc = XDocument . Load ( projectFile ) ;
378-
379- var element = xdoc . XPathSelectElement ( "//PropertyGroup/SelfContained" ) ;
380-
381- if ( bool . TryParse ( element ? . Value , out _ ) )
361+ var properties = LookupProjectProperties ( projectLocation , "SelfContained" ) ;
362+ if ( properties . TryGetValue ( "SelfContained" , out var selfContained ) )
382363 {
383- return true ;
364+ return bool . TryParse ( selfContained , out _ ) ;
384365 }
385366
386367 return false ;
387368 }
388369
389- public static string FindProjectFileInDirectory ( string directory )
370+ private static string FindProjectFileInDirectory ( string directory )
390371 {
391372 if ( File . Exists ( directory ) )
392373 return directory ;
0 commit comments