dotnet / msbuild

The Microsoft Build Engine (MSBuild) is the build platform for .NET and Visual Studio.
https://docs.microsoft.com/visualstudio/msbuild/msbuild
MIT License
5.21k stars 1.35k forks source link

[Broken Build]: FluentMigrator.MSBuild sample won't work on net8.0 #10750

Open jzabroski opened 1 week ago

jzabroski commented 1 week ago

Issue Description

FluentMigrator.MSBuild version 6.1.4 is packaged following guidance here: this project references nuget package FluentMigrator.MSBuild, which was packaged following the guidance here: https://learn.microsoft.com/en-us/visualstudio/msbuild/tutorial-custom-task-code-generation?view=vs-2022#create-a-nuget-package

The problem is that as I am loading an assembly as part of the target, for some reason the reflection calls are failing, even though it looks to me like all the assembly versions match (6.1.4). - This works on .NET Framework 4.8 (TFM net48), but fails on net8.0

The other thing I am looking at is GenerateTemporaryTargetAssemblyTask

Steps to Reproduce

Sample project here: https://github.com/fluentmigrator/fluentmigrator/tree/main/samples/FluentMigrator.Example.MSBuild

To run: dotnet.exe msbuild .\samples\FluentMigrator.Example.MSBuild\SampleMigrator.csproj

Requires a local database server to run - SQL Server localdb is fine. If using localdb, you just need to update the connection string appropriately and create an empty FluentMigratorExample database, then you can run the target as described above.

I ran it using:

MSBuild version 17.11.3+0c8610977 for .NET

and

PS D:\source\fluentmigrator\> dotnet.exe --list-sdks
6.0.321 [C:\Program Files\dotnet\sdk]
8.0.400 [C:\Program Files\dotnet\sdk]

PS D:\source\fluentmigrator\> dotnet.exe --list-runtimes
Microsoft.AspNetCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.33 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Note, this works correctly with a .NET CLI tool - the only difference is the entrypoint - one is MSBuild custom task, the other is a CLI tool. They share much of the same code.

dotnet new tool-manifest
dotnet install FluentMigrator.DotNet.Cli --local
dotnet tool run dotnet-fm migrate --processor sqlserver2016 --assembly "D:\source\fluentmigrator\samples\FluentMigrator.Example.Migrations\bin\Debug\net8.0\FluentMigrator.Example.Migrations.dll" --connection "Server=(local);Initial Catalog=FluentMigratorExample;Integrated Security=true;TrustServerCertificate=true;Encrypt=true" --include-untagged-migrations

Expected Behavior

Migrations run - no red ink errors should occur - the output should say something similar to the equivalent FluentMigrator.DotNet.Cli tool output, as the two packages use the same TaskExecutor and basically the same Microsoft DI configuration.

Actual Behavior

The error I get is:

D:\source\fluentmigrator\samples\FluentMigrator.Example.MSBuild\SampleMigrator.csproj(17,5): error : While executing mi
grations the following error was encountered: No migrations found,    at FluentMigrator.Runner.DefaultMigrationInformat
ionLoader.FindMigrations(IMigrationSource source, IMigrationRunnerConventions conventions, String namespace, Boolean lo
adNestedNamespaces, String[] tagsToMatch, Boolean includeUntagged) in D:\a\1\s\src\FluentMigrator.Runner.Core\DefaultMi
grationInformationLoader.cs:line 185

Typically, this is not a hard error message to figure out and I've documented in our FAQ the common causes. However, what stumps me here is I checked all the common causes and they're not the issue.

Ask us questions

~1. Is there a bridge between MSBuild's ILogger and Microsoft DI ILogger I can use? Much of the logic that is failing is not in my MSBuild assembly, but in a common shared assembly that uses Microsoft DI ILogger instead. Having a shim I can wire up would make it a lot easier to debug this problem.~

  1. Is there something I am missing with running dotnet.exe msbuild that could be a problem here?

  2. Could how I am publishing the FluentMigrator.MSBuild task be a problem? Like, somehow it embeds the wrong reference to an assembly? How would I diagnose that?

  3. Would [GenerateTemporaryTargetAssembly task[(https://learn.microsoft.com/en-us/visualstudio/msbuild/generatetemporarytargetassembly-task?view=vs-2022) be a better approach? I've never done it so I am a little intimidated it will be a time suck that goes nowhere. There's limited samples I can find that approximate what I am doing.

jzabroski commented 1 week ago

After debugging this for another full day,

  1. I was able to create a logging shim for MSBuild's ILogger for Microsoft.Exensions.Logging - crossing that question off.
  2. I am wondering why two types would have the same AssemblyFullyQualifiedName and the type hierarchy matches all the way up, including interfaces, but still fail type(IMigration).IsAssignableFrom(myForwardOnlyMigrationInstance).

There has to be some obscure scenario in the .NET runtime causing this woe I am facing? The two interfaces are:

FluentMigrator.IMigration, FluentMigrator.Abstractions, Version=6.1.4.0, Culture=neutral, PublicKeyToken=aacfc7de5acabf05

FluentMigrator.IMigration, FluentMigrator.Abstractions, Version=6.1.4.0, Culture=neutral, PublicKeyToken=aacfc7de5acabf05

jzabroski commented 1 week ago

I still can't figure this out. This is just bizarre. I see no evidence this shouldn't be working. I added a DirtyAssemblyResolveHelper to the FluentMigrator.MSBuild project, and it doesn't fix whatever the issue is.

I can make DirtyAssemblyResolveHelper stateful and inject an ILogger, I suppose, and trace out any redirects to see what is or isn't being handled. (Functionally, this is simpler than assembly fusion logging, as it would only really come into play calling this one task, vs the entire msbuild build chain)

JanKrivanek commented 1 week ago

Thank you @jzabroski for reporting the issue

Can you help us in focusing the investigation via providing:

Thank you