SDK per i progetti .NET
I progetti .NET moderni sono associati a un software development kit (SDK) del progetto. Ogni SDK di progetto è un set di destinazioni di MSBuild e attività associate responsabili della compilazione, della compressione e della pubblicazione del codice. Un progetto che fa riferimento a un SDK di progetto viene talvolta definito progetto in stile SDK.
SDK disponibili
Sono disponibili gli SDK seguenti:
ID | Descrizione | Repository |
---|---|---|
Microsoft.NET.Sdk |
.NET SDK | https://github.com/dotnet/sdk |
Microsoft.NET.Sdk.Web |
Web SDK di .NET | https://github.com/dotnet/sdk |
Microsoft.NET.Sdk.Razor |
Razor SDK di .NET | https://github.com/dotnet/aspnetcore |
Microsoft.NET.Sdk.BlazorWebAssembly |
SDK Blazor WebAssembly di .NET | https://github.com/dotnet/aspnetcore |
Microsoft.NET.Sdk.Worker |
SDK Worker Service di .NET | |
Aspire.AppHost.Sdk |
The .NET Aspire SDK | https://github.com/dotnet/aspire |
MSTest.Sdk |
MSTest SDK | https://github.com/microsoft/testfx |
.NET SDK è l'SDK di base per .NET. Gli altri SDK fanno riferimento a .NET SDK e tutte le proprietà di .NET SDK sono disponibili per i progetti associati agli altri SDK. Web SDK ad esempio dipende sia da .NET SDK sia da Razor SDK.
È anche possibile creare un SDK personalizzato che può essere distribuito tramite NuGet.
Per i progetti Windows Form e Windows Presentation Foundation (WPF), specificare .NET SDK (Microsoft.NET.Sdk
) e impostare alcune proprietà aggiuntive nel file di progetto. Per altre informazioni, vedere Abilitare .NET Desktop SDK.
File di progetto
I progetti .NET sono basati sul formato MSBuild. I file di progetto, con estensioni come csproj per i progetti C# e fsproj per i progetti F#, sono in formato XML. L'elemento radice di un file di progetto MSBuild è l'elemento Project. L'elemento Project
ha un attributo Sdk
facoltativo che specifica quale SDK (e versione) usare. Per usare gli strumenti .NET e compilare il codice, impostare l'attributo Sdk
su uno degli ID nella tabella SDK disponibili.
<Project Sdk="Microsoft.NET.Sdk">
...
</Project>
A partire da .NET Aspire 9, l'esempio precedente potrebbe invece usare .NET Aspire SDK.
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0-rc.1.24511.1" />
<!-- Omitted for brevity... -->
</Project>
Per altre informazioni, vedere Strumenti e configurazione di .NET Aspire.
Per specificare un SDK proveniente da NuGet, includere la versione alla fine del nome o specificare il nome e la versione nel file global.json.
<Project Sdk="MSBuild.Sdk.Extras/2.0.54">
...
</Project>
Un altro modo per specificare l'SDK consiste nell'usare l'elemento Sdk
di primo livello:
<Project>
<Sdk Name="Microsoft.NET.Sdk" />
...
</Project>
Fare riferimento a un SDK in uno di questi modi semplifica notevolmente i file di progetto per .NET. Durante la valutazione del progetto, MSBuild aggiunge importazioni implicite per Sdk.props
nella parte superiore del file di progetto e Sdk.targets
nella parte inferiore.
<Project>
<!-- Implicit top import -->
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
...
<!-- Implicit bottom import -->
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>
Suggerimento
In un computer Windows i file Sdk.props e Sdk.targets sono disponibili nella cartella %Programmi%\dotnet\sdk\[version]\Sdks\Microsoft.NET.Sdk\Sdk.
Pre-elaborare il file di progetto
È possibile visualizzare il progetto completamente espanso, nel modo in cui viene visualizzato da MSBuild dopo che l'SDK e le relative destinazioni sono incluse usando il comando dotnet msbuild -preprocess
. L'opzione preprocess del comando dotnet msbuild
mostra quali file vengono importati, le rispettive origini e i relativi contributi alla build senza compilare effettivamente il progetto.
Se il progetto ha più framework di destinazione, concentrare i risultati del comando su un solo framework specificandolo come proprietà di MSBuild. Ad esempio:
dotnet msbuild -property:TargetFramework=net8.0 -preprocess:output.xml
Inclusioni ed esclusioni predefinite
Le inclusioni ed esclusioni predefinite per gli elementi Compile
, le risorse incorporate e gli elementi None
vengono definite nell'SDK. A differenza dei progetti .NET Framework non SDK, non è necessario specificare questi elementi nel file di progetto, perché le impostazioni predefinite coprono i casi d'uso più comuni. Questo comportamento rende il file di progetto più piccolo e più facile da comprendere e modificare manualmente, se necessario.
La tabella seguente mostra gli elementi e i glob inclusi ed esclusi nell'SDK:
Elemento | GLOB Include | GLOB Exclude | GLOB Remove |
---|---|---|---|
Compile | **/*.cs (o altre estensioni del linguaggio) | **/*.user; **/*.*proj; **/*.sln; **/*.vssscc | N/D |
EmbeddedResource | **/*.resx | **/*.user; **/*.*proj; **/*.sln; **/*.vssscc | N/D |
None | **/* | **/*.user; **/*.*proj; **/*.sln; **/*.vssscc | **/*.cs; **/*.resx |
Nota
Le cartelle ./bin
e ./obj
, rappresentate dalle proprietà $(BaseOutputPath)
e $(BaseIntermediateOutputPath)
di MSBuild, vengono escluse dai glob per impostazione predefinita. Le esclusioni sono rappresentate dalla proprietà DefaultItemExcludes.
.NET Desktop SDK ha inclusioni ed esclusioni aggiuntive per WPF. Per altre informazioni, vedere Inclusioni ed esclusioni predefinite per WPF.
Se si definisce in modo esplicito uno di questi elementi nel file di progetto, è probabile che venga visualizzato un errore di compilazione NETSDK1022. Per informazioni su come risolvere l'errore, vedere NETSDK1022: Elementi duplicati inclusi.
Direttive using implicite
A partire da .NET 6, le direttive global using
implicite vengono aggiunte ai nuovi progetti C#. Ciò significa che è possibile usare i tipi definiti in questi spazi dei nomi senza dover specificare il nome completo o aggiungere manualmente una direttiva using
. L'aspetto implicito fa riferimento al fatto che le direttive global using
vengono aggiunte a un file generato nella directory obj del progetto.
Vengono aggiunte direttive global using
implicite per i progetti che usano uno degli SDK seguenti:
Microsoft.NET.Sdk
Microsoft.NET.Sdk.Web
Microsoft.NET.Sdk.Worker
Microsoft.NET.Sdk.WindowsDesktop
Viene aggiunta una direttiva global using
per ogni spazio dei nomi in un set di spazi dei nomi predefiniti basati sull'SDK di progetto. Questi spazi dei nomi predefiniti sono illustrati nella tabella seguente.
SDK | Spazi dei nomi predefiniti |
---|---|
Microsoft.NET.Sdk | System System.Collections.Generic System.IO System.Linq System.Net.Http System.Threading System.Threading.Tasks |
Microsoft.NET.Sdk.Web | Spazi dei nomi Microsoft.NET.Sdk System.Net.Http.Json Microsoft.AspNetCore.Builder Microsoft.AspNetCore.Hosting Microsoft.AspNetCore.Http Microsoft.AspNetCore.Routing Microsoft.Extensions.Configuration Microsoft.Extensions.DependencyInjection Microsoft.Extensions.Hosting Microsoft.Extensions.Logging |
Microsoft.NET.Sdk.Worker | Spazi dei nomi Microsoft.NET.Sdk Microsoft.Extensions.Configuration Microsoft.Extensions.DependencyInjection Microsoft.Extensions.Hosting Microsoft.Extensions.Logging |
Microsoft.NET.Sdk.WindowsDesktop (Windows Forms) | Spazi dei nomi Microsoft.NET.Sdk System.Drawing System.Windows.Forms |
Microsoft.NET.Sdk.WindowsDesktop (WPF) | Spazi dei nomi Microsoft.NET.Sdk System.IO rimosso System.Net.Http rimosso |
Se si vuole disabilitare questa funzionalità o se si vogliono abilitare direttive global using
implicite in un progetto C# esistente, è possibile farlo tramite la proprietà ImplicitUsings
di MSBuild.
È possibile specificare ulteriori direttive global using
implicite aggiungendo elementi Using
o Import
elementi per i progetti di Visual Basic al file di progetto, ad esempio:
<ItemGroup>
<Using Include="System.IO.Pipes" />
</ItemGroup>
Riferimenti impliciti al pacchetto
Quando il progetto è destinato a .NET Standard 1.0-2.0, .NET SDK aggiunge riferimenti impliciti a determinati metapacchetti. Un metapacchetto è un pacchetto basato su framework costituito solo da dipendenze da altri pacchetti. È possibile fare riferimento ai metapacchetti in modo implicito in base ai framework di destinazione specificati nella proprietà TargetFramework o TargetFrameworks (plurale) del file di progetto.
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
</PropertyGroup>
Se necessario, è possibile disabilitare i riferimenti impliciti ai pacchetti usando la proprietà DisableImplicitFrameworkReferences e aggiungere riferimenti espliciti solo ai framework o ai pacchetti necessari.
Raccomandazioni:
- Quando la destinazione è .NET Framework o .NET Standard 1.0-2.0, non aggiungere un riferimento esplicito ai metapacchetti
NETStandard.Library
tramite un elemento<PackageReference>
nel file di progetto. Per i progetti .NET Standard 1.0-2.0 viene fatto riferimento in modo implicito a questi metapacchetti. Per i progetti .NET Framework, se è necessaria una versione diNETStandard.Library
quando si usa un pacchetto NuGet basato su .NET Standard, NuGet installa automaticamente tale versione. - Se è necessaria una versione specifica del metapacchetto
NETStandard.Library
quando la destinazione è .NET Standard 1.0-2.0, è possibile usare la proprietà<NetStandardImplicitPackageVersion>
e impostare la versione necessaria.
Eventi di compilazione
Nei progetti in stile SDK usare una destinazione MSBuild denominata PreBuild
o PostBuild
e impostare la proprietà BeforeTargets
per PreBuild
o la proprietà AfterTargets
per PostBuild
.
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command=""$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)"" />
</Target>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="echo Output written to $(TargetDir)" />
</Target>
Nota
- È possibile usare qualsiasi nome per le destinazioni MSBuild. L'IDE di Visual Studio riconosce tuttavia le destinazioni
PreBuild
ePostBuild
, quindi usando tali nomi è possibile modificare i comandi nell'IDE. - Le proprietà
PreBuildEvent
ePostBuildEvent
non sono consigliate nei progetti in stile SDK, perché le macro come$(ProjectDir)
non vengono risolte. Ad esempio, il codice seguente non è supportato:
<PropertyGroup>
<PreBuildEvent>"$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)"</PreBuildEvent>
</PropertyGroup>
Personalizzare la compilazione
Esistono diversi modi per personalizzare una compilazione. È consigliabile eseguire l'override di una proprietà passandola come argomento al comando msbuild o dotnet. È anche possibile aggiungere la proprietà al file di progetto o a un file Directory.Build.props. Per un elenco di proprietà utili per i progetti .NET, vedere Informazioni di riferimento su MSBuild per i progetti .NET SDK.
Suggerimento
Un modo semplice per creare un nuovo file Directory.Build.props dalla riga di comando consiste nell'usare il comando dotnet new buildprops
nella radice del repository.
Destinazioni personalizzate
I progetti .NET possono creare pacchetti di destinazioni e proprietà di MSBuild personalizzate per l'uso da parte di progetti che utilizzano il pacchetto. Usare questo tipo di estendibilità quando si vuole:
- Estendere il processo di compilazione.
- Accedere agli artefatti del processo di compilazione, ad esempio i file generati.
- Esaminare la configurazione in cui viene richiamata la compilazione.
È possibile aggiungere destinazioni o proprietà di compilazione personalizzate inserendo i file nel formato <package_id>.targets
o <package_id>.props
(ad esempio, Contoso.Utility.UsefulStuff.targets
) nella cartella build del progetto.
Il codice XML seguente è un frammento di codice di un file con estensione csproj che indica al comando dotnet pack
cosa inserire nel pacchetto. L'elemento <ItemGroup Label="dotnet pack instructions">
inserisce i file di destinazione nella cartella build all'interno del pacchetto. L'elemento <Target Name="CollectRuntimeOutputs" BeforeTargets="_GetPackageFiles">
inserisce gli assembly e i file json nella cartella build.
<Project Sdk="Microsoft.NET.Sdk">
...
<ItemGroup Label="dotnet pack instructions">
<Content Include="build\*.targets">
<Pack>true</Pack>
<PackagePath>build\</PackagePath>
</Content>
</ItemGroup>
<Target Name="CollectRuntimeOutputs" BeforeTargets="_GetPackageFiles">
<!-- Collect these items inside a target that runs after build but before packaging. -->
<ItemGroup>
<Content Include="$(OutputPath)\*.dll;$(OutputPath)\*.json">
<Pack>true</Pack>
<PackagePath>build\</PackagePath>
</Content>
</ItemGroup>
</Target>
...
</Project>
Per utilizzare una destinazione personalizzata nel progetto, aggiungere un elemento PackageReference
che punta al pacchetto e alla relativa versione. A differenza degli strumenti, il pacchetto di destinazioni personalizzate è incluso nella chiusura delle dipendenze del progetto che le utilizza.
È possibile configurare come usare la destinazione personalizzata. Dal momento che si tratta di una destinazione MSBuild, può dipendere da una destinazione specifica, essere eseguita dopo un'altra destinazione e anche essere chiamata manualmente mediante il comando dotnet msbuild -t:<target-name>
. Per offrire un'esperienza utente migliore, è tuttavia possibile combinare strumenti per progetto e destinazioni personalizzate. In questo scenario lo strumento per progetto accetta tutti i parametri necessari e li converte nella chiamata di dotnet msbuild
richiesta che esegue la destinazione. È possibile visualizzare un esempio di questo tipo di sinergia nel repository degli esempi di MVP Summit 2016 Hackathon nel progetto dotnet-packer
.