Skip to content
Denis Kuzmin [ GitHub/3F ] edited this page Oct 15, 2019 · 5 revisions

Custom loading of projects

MvsSln provides related virtual methods for your convenience since we're still using the original MS implementation for work with project files.

As the real example, the .NET DllExport project uses this way to avoid some problems when loading unsupported project types:

That is, you can easily try to override actual loading with any custom logic as you need. For example:

+Microsoft.Build.dll //  ~ it could be custom reference in your env

using net.r_eg.MvsSln;
using net.r_eg.MvsSln.Core;
...

public class MyEnv: IsolatedEnv, IEnvironment, IDisposable
{
    public MyEnv(ISlnResult data)
        : base(data)
    {

    }

    protected override Microsoft.Build.Evaluation.Project Load(string path, IDictionary<string, string> properties)
    {
        return base.Load(path, properties); //TODO: your awesome logic 
    }
    
    protected override void Dispose(bool disposing) => base.Dispose(disposing);
}
...

Please note: 2.4 introduces XProjectEnv (spitted IsolatedEnv as the base but without IDisposable) [?]

Now, just provide your implementation for MvsSln. For example:

using(var sln = new Sln(file, SlnItems.Projects
                                | SlnItems.SolutionConfPlatforms
                                | SlnItems.ProjectConfPlatforms))
{
    IEnvironment env = new MyEnv(sln.Result);
    env.LoadMinimalProjects();
    ...

    sln.Result.ProjectItems.Where(p => p.path == "special\\projectfile.csproj");
    ...
}

Custom MSBuild Resolver

Although MvsSln provides native implementation for most of the features, however, part of the code still (we're considering future replacement, follow the news) relies on original MS implementation.

But modern Microsoft.Build assemblies are much more closely integrated with Visual Studio and much more difficult to maintain independently (ie. without VS/dotnet sdk dependencies).

About [ possible ] problems

Today you may note the following possible problems when using our Env features (flags: Env | LoadDefaultData; or Env | LoadMinimalDefaultData).

For example:

using(var sln = new Sln(path, SlnItems.Env | SlnItems.LoadMinimalDefaultData))
{
    //...
}

It may produce the following:

Microsoft.Build.Exceptions.InvalidProjectFileException:

The imported project "<...>" was not found. Confirm that the path in the 
<Import> declaration is correct, and that the file exists on disk.

Due to import sections when loading project files:

<Import Project="..." />

For something like this: Microsoft.CSharp.targets, Microsoft.Common.props, Microsoft.Cpp.Default.props, Microsoft.Cpp.targets, ...

Or it also may produce the following:

Microsoft.Build.Exceptions.InvalidProjectFileException: 
The SDK 'Microsoft.NET.Sdk' specified could not be found.

Due to SDK-based project type:

<Project Sdk="Microsoft.NET.Sdk">...</Project>

Solutions for MvsSln 2.x

Microsoft.Build.Locator

This package Microsoft.Build.Locator is official solution from MS. That was based on two things:

  1. Spoofing assembly from installed instance of Visual Studio.
    1. Either Microsoft.VisualStudio.Setup.Configuration.Interop API to query installed Visual Studio instances. [?src]
    2. Or through VS dev console. [?src]
  2. (.NET Core) Manual msbuild path through MSBUILD_EXE_PATH environment variable by using available dotnet Sdk paths.

Here's implementation: https://github.com/microsoft/MSBuildLocator/blob/87bebc8b2014f0b52110cf46500d805bba3e072c/src/MSBuildLocator/MSBuildLocator.cs#L114

The first method is the most problematic due to isolation and actually spoofing the assembly.

We will never provide something like this together with MvsSln! Because it will require patching on your side anyway, like below.

Thus, just add this:

Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults();

Before using MvsSln, for example:

// your assembly

MSBuildLocator.RegisterDefaults();

// ... before MvsSln

using(var sln = new Sln(path, SlnItems.Env | SlnItems.LoadMinimalDefaultData))
{
    // your assembly will be fixed via the first or the second way in MSBuildLocator
}

MSBUILD_EXE_PATH environment variable

Microsoft.Build.Locator above already implements this way, however, you can do it manually.

Just add this:

System.Environment.SetEnvironmentVariable("MSBUILD_EXE_PATH", "fullpath to msbuild dll with env");

Before using MvsSln, for example:

System.Environment.SetEnvironmentVariable(
    "MSBUILD_EXE_PATH", 
    @"C:\Program Files\dotnet\sdk\3.0.100\MSBuild.dll", 
    EnvironmentVariableTarget.Process
);

using(var sln = new Sln(@"D:\tmp\_Issues\MvsSln\PkgRef\ConsoleApp1\ConsoleApp1.sln", SlnItems.Env | SlnItems.LoadMinimalDefaultData)) {
    //...
}
Microsoft.NET.Sdk. Why does it work?
  1. MSBUILD_EXE_PATH feature is already implemented by MSBuild inside for work in other environment like dotnet sdk or Visual Studio.
  2. dotnet SDK conatins Sdk Resolver (Microsoft.Build.NuGetSdkResolver.dll) that will be used due to:
<!-- SdkResolvers\Microsoft.Build.NuGetSdkResolver\Microsoft.Build.NuGetSdkResolver.xml -->
<SdkResolver>
  <Path>..\..\Microsoft.Build.NuGetSdkResolver.dll</Path>
</SdkResolver>

This env finally helps to resolve SDK-based project type, and now you can process it:

<Project Sdk="Microsoft.NET.Sdk">...</Project>

And more because of other environment such as dotnet sdk etc.

Manual detecting full path to dotnet sdk

Here's official MS way: https://github.com/microsoft/MSBuildLocator/blob/87bebc8b2014f0b52110cf46500d805bba3e072c/src/MSBuildLocator/DotNetSdkLocationHelper.cs#L61

dotnet --list-sdks

1.0.4 [C:\Program Files\dotnet\sdk]
1.1.0 [C:\Program Files\dotnet\sdk]
2.0.2 [C:\Program Files\dotnet\sdk]
2.0.3 [C:\Program Files\dotnet\sdk]
2.1.2 [C:\Program Files\dotnet\sdk]
2.1.4 [C:\Program Files\dotnet\sdk]
2.1.100 [C:\Program Files\dotnet\sdk]
2.1.101 [C:\Program Files\dotnet\sdk]
2.1.102 [C:\Program Files\dotnet\sdk]
2.1.103 [C:\Program Files\dotnet\sdk]
2.1.201 [C:\Program Files\dotnet\sdk]
2.1.202 [C:\Program Files\dotnet\sdk]
2.1.401 [C:\Program Files\dotnet\sdk]
2.1.402 [C:\Program Files\dotnet\sdk]
2.1.403 [C:\Program Files\dotnet\sdk]
2.1.503 [C:\Program Files\dotnet\sdk]
2.1.505 [C:\Program Files\dotnet\sdk]
2.1.507 [C:\Program Files\dotnet\sdk]
2.1.508 [C:\Program Files\dotnet\sdk]
2.1.509 [C:\Program Files\dotnet\sdk]
2.1.801 [C:\Program Files\dotnet\sdk]
3.0.100 [C:\Program Files\dotnet\sdk]

Still have the problem / question

Do not hesitate to contact. https://github.com/3F/MvsSln/issues

Clone this wiki locally