diff --git a/src/MSBuildLocator/MSBuildLocator.cs b/src/MSBuildLocator/MSBuildLocator.cs index e17abc2e..e2fbab52 100644 --- a/src/MSBuildLocator/MSBuildLocator.cs +++ b/src/MSBuildLocator/MSBuildLocator.cs @@ -139,14 +139,50 @@ public static void RegisterInstance(VisualStudioInstance instance) /// public static void RegisterMSBuildPath(string msbuildPath) { - if (string.IsNullOrWhiteSpace(msbuildPath)) + RegisterMSBuildPath(new string[] { + msbuildPath +#if NET46 + // Finds and loads NuGet assemblies if msbuildPath is in a VS installation + , Path.GetFullPath(Path.Combine(msbuildPath, "..", "..", "..", "Common7", "IDE", "CommonExtensions", "Microsoft", "NuGet")) +#endif + }); + } + + /// + /// Add assembly resolution for Microsoft.Build core dlls in the current AppDomain from the specified + /// path. + /// + /// + /// Paths to directories containing a deployment of MSBuild binaries. + /// A minimal MSBuild deployment would be the publish result of the Microsoft.Build.Runtime package. + /// + /// In order to restore and build real projects, one needs a deployment that contains the rest of the toolchain (nuget, compilers, etc.). + /// Such deployments can be found in installations such as Visual Studio or dotnet CLI. + /// + public static void RegisterMSBuildPath(string[] msbuildSearchPaths) + { + if (msbuildSearchPaths.Length < 1) { - throw new ArgumentException("Value may not be null or whitespace", nameof(msbuildPath)); + throw new ArgumentException("Must provide at least one search path to RegisterMSBuildPath."); } - if (!Directory.Exists(msbuildPath)) + List nullOrWhiteSpaceExceptions = new List(); + for (int i = 0; i < msbuildSearchPaths.Length; i++) { - throw new ArgumentException($"Directory \"{msbuildPath}\" does not exist", nameof(msbuildPath)); + if (string.IsNullOrWhiteSpace(msbuildSearchPaths[i])) + { + nullOrWhiteSpaceExceptions.Add(new ArgumentException($"Value at position {i+1} may not be null or whitespace", nameof(msbuildSearchPaths))); + } + } + if (nullOrWhiteSpaceExceptions.Count > 0) + { + throw new AggregateException("Search paths for MSBuild assemblies cannot be null and must contain non-whitespace characters.", nullOrWhiteSpaceExceptions); + } + + IEnumerable paths = msbuildSearchPaths.Where(path => !Directory.Exists(path)); + if (paths.FirstOrDefault() == null) + { + throw new AggregateException($"A directory or directories in \"{nameof(msbuildSearchPaths)}\" do not exist", paths.Select(path => new ArgumentException($"Directory \"{path}\" does not exist", nameof(msbuildSearchPaths)))); } if (!CanRegister) @@ -202,12 +238,15 @@ Assembly TryLoadAssembly(AssemblyName assemblyName) // Look in the MSBuild folder for any unresolved reference. It may be a dependency // of MSBuild or a task. - string targetAssembly = Path.Combine(msbuildPath, assemblyName.Name + ".dll"); - if (File.Exists(targetAssembly)) + foreach (string msbuildPath in msbuildSearchPaths) { - assembly = Assembly.LoadFrom(targetAssembly); - loadedAssemblies.Add(assemblyName.FullName, assembly); - return assembly; + string targetAssembly = Path.Combine(msbuildPath, assemblyName.Name + ".dll"); + if (File.Exists(targetAssembly)) + { + assembly = Assembly.LoadFrom(targetAssembly); + loadedAssemblies.Add(assemblyName.FullName, assembly); + return assembly; + } } return null;