Optie op oplossingsniveau --output
is niet meer geldig voor build-gerelateerde opdrachten
In de SDK 7.0.200 was er een wijziging om de --output
/-o
optie niet meer te accepteren bij het gebruik van een oplossingsbestand met de volgende opdrachten:
build
clean
pack
publish
store
test
vstest
Dit komt doordat de semantiek van de OutputPath
eigenschap, die wordt beheerd door de --output
/-o
optie, niet goed is gedefinieerd voor oplossingen. Projecten die op deze manier zijn gebouwd, hebben hun uitvoer in dezelfde map geplaatst, wat inconsistent is en heeft geleid tot een aantal door de gebruiker gerapporteerde problemen.
Deze wijziging is gereduceerd tot een waarschuwingsniveau van ernst in de SDK 7.0.201 en pack
is verwijderd uit de lijst met opdrachten die worden beïnvloed.
Versie geïntroduceerd
.NET 7.0.200 SDK, beperkt tot een waarschuwing alleen in de SDK 7.0.201.
Vorig gedrag
Als u eerder hebt opgegeven --output
/-o
bij het gebruik van een oplossingsbestand, wordt de uitvoer voor alle gemaakte projecten in de opgegeven map geplaatst in een niet-gedefinieerde en inconsistente volgorde.
Nieuw gedrag
De dotnet
CLI krijgt een foutmelding als de --output
/-o
optie wordt gebruikt met een oplossingsbestand. Vanaf de SDK 7.0.201 wordt in plaats daarvan een waarschuwing verzonden en wordt er dotnet pack
geen waarschuwing of fout gegenereerd.
Type wijziging die fouten veroorzaken
Deze belangrijke wijziging kan wijzigingen vereisen voor het bouwen van scripts en pijplijnen voor continue integratie. Als gevolg hiervan is dit van invloed op zowel binaire als broncompatibiliteit.
Reden voor wijziging
Deze wijziging is aangebracht omdat de semantiek van de OutputPath
eigenschap, die wordt beheerd door de --output
/-o
optie, niet goed zijn gedefinieerd voor oplossingen. Projecten die op deze manier zijn gebouwd, hebben hun uitvoer in dezelfde map geplaatst, wat inconsistent is en heeft geleid tot een aantal door de gebruiker gerapporteerde problemen.
Wanneer een oplossing is gebouwd met de --output
optie, wordt de OutputPath
eigenschap ingesteld op dezelfde waarde voor alle projecten, wat betekent dat alle projecten hun uitvoer in dezelfde map hebben geplaatst. Afhankelijk van de complexiteit van de projecten in de oplossing kunnen er verschillende en inconsistente resultaten optreden. Laten we eens kijken naar enkele voorbeelden van verschillende oplossingsshapes en hoe deze worden beïnvloed door een gedeelde OutputPath
oplossing.
Eén project, één TargetFramework
Stel u een oplossing voor die één project bevat dat gericht is op één TargetFramework
, net7.0
. In dit geval is het instellen van de eigenschap in het projectbestand gelijk aan het --output
instellen van de OutputPath
eigenschap. Tijdens een build (of andere opdrachten, maar laten we de discussie nu bepalen om te bouwen), worden alle uitvoer voor het project in de opgegeven map geplaatst.
Eén project, meerdere TargetFrameworks
Stel u nu een oplossing voor die één project bevat met meerdere TargetFrameworks
, net6.0
en net7.0
. Vanwege meerdere targeting wordt het project twee keer gebouwd, één keer voor elk TargetFramework
. Voor elk van deze 'inner'-builds wordt de OutputPath
waarde ingesteld op dezelfde waarde, zodat de uitvoer voor elk van de binnenste builds in dezelfde map wordt geplaatst. Dit betekent dat elke voltooide build de uitvoer van de andere build overschrijft en dat in een parallel-buildsysteem zoals MSBuild standaard 'last' is ingesteld.
Library = Console =>> Test, single TargetFramework
Stel nu een oplossing voor die een bibliotheekproject bevat, een consoleproject dat verwijst naar het bibliotheekproject en een testproject dat verwijst naar het consoleproject. Al deze projecten zijn gericht op één TargetFramework
, net7.0
. In dit geval wordt het bibliotheekproject eerst gebouwd en vervolgens wordt het consoleproject gebouwd. Het testproject wordt als laatste gebouwd en verwijst naar het consoleproject. Voor elk gebouwd project worden de uitvoer van elke build gekopieerd naar de map die door de OutputPath
map is opgegeven en bevat de uiteindelijke map dus assets van alle drie de projecten. Dit werkt voor het testen, maar voor publicatie kan het leiden tot testassets die naar productie worden verzonden.
Library = Console =>> Test, meerdere TargetFrameworks
Neem nu dezelfde keten van projecten en voeg er naast de net7.0
build een net6.0
TargetFramework
build aan toe. Hetzelfde probleem als de single-project, multi-targeted build treedt op: inconsistent kopiëren van TFM-specifieke assets naar de opgegeven map.
Meerdere apps
Tot nu toe hebben we gekeken naar scenario's met een lineaire afhankelijkheidsgrafiek, maar veel oplossingen kunnen meerdere gerelateerde toepassingen bevatten. Dit betekent dat meerdere apps gelijktijdig kunnen worden gebouwd in dezelfde uitvoermap. Als de apps een afhankelijkheidsbestand met dezelfde naam bevatten, kan de build af en toe mislukken wanneer meerdere projecten gelijktijdig proberen naar dat bestand te schrijven in het uitvoerpad.
Als meerdere apps afhankelijk zijn van verschillende versies van een bestand, kan zelfs als de build slaagt, welke versie van het bestand wordt gekopieerd naar het uitvoerpad mogelijk niet deterministisch zijn. Dit kan gebeuren wanneer de projecten afhankelijk zijn (mogelijk transitief) van verschillende versies van een NuGet-pakket. Binnen één project zorgt NuGet ervoor dat de afhankelijkheden (inclusief eventuele transitieve afhankelijkheden via NuGet-pakketten en/of projectverwijzingen) zijn geïntegreerd in dezelfde versie. Omdat de eenwording wordt uitgevoerd binnen de context van één project en de afhankelijke projecten, betekent dit dat het mogelijk is om verschillende versies van een pakket op te lossen wanneer twee afzonderlijke projecten op het hoogste niveau worden gebouwd. Als het project dat afhankelijk is van de hogere versie de afhankelijkheid voor het laatst kopieert, worden de apps vaak uitgevoerd. Als de lagere versie echter voor het laatst wordt gekopieerd, kan de assembly tijdens runtime niet worden geladen door de app die is gecompileerd op basis van de hogere versie. Omdat de gekopieerde versie niet-deterministisch kan zijn, kan dit leiden tot sporadische, onbetrouwbare builds waar het erg moeilijk is om het probleem te diagnosticeren.
Andere voorbeelden
Zie de discussie over dotnet/sdk#15607 voor meer voorbeelden van hoe deze onderliggende fout in de praktijk wordt weergegeven.
Aanbevolen actie
De algemene aanbeveling is om de actie uit te voeren die u eerder hebt uitgevoerd zonder de --output
/-o
optie en de uitvoer vervolgens naar de gewenste locatie te verplaatsen nadat de opdracht is voltooid. Het is ook mogelijk om de actie op een specifiek project uit te voeren en nog steeds de --output
/-o
optie toe te passen, omdat deze meer goed gedefinieerde semantiek heeft.
Als u het bestaande gedrag exact wilt behouden, kunt u de --property
vlag gebruiken om een MSBuild-eigenschap in te stellen op de gewenste map. De te gebruiken eigenschap varieert op basis van de opdracht:
Opdracht | Eigenschappen | Opmerking |
---|---|---|
build |
OutputPath |
dotnet build --property:OutputPath=DESIRED_PATH |
clean |
OutputPath |
dotnet clean --property:OutputPath=DESIRED_PATH |
pack |
PackageOutputPath |
dotnet pack --property:PackageOutputPath=DESIRED_PATH |
publish |
PublishDir |
dotnet publish --property:PublishDir=DESIRED_PATH |
store |
OutputPath |
dotnet store --property:OutputPath=DESIRED_PATH |
test |
TestResultsDirectory |
dotnet test --property:OutputPath=DESIRED_PATH |
OPMERKING Voor de beste resultaten moet de DESIRED_PATH een absoluut pad zijn. Relatieve paden worden 'verankerd' (d.w. absoluut gemaakt) op manieren die u mogelijk niet verwacht en werken mogelijk niet hetzelfde met alle opdrachten.