Condividi tramite


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 di NETStandard.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="&quot;$(ProjectDir)PreBuildEvent.bat&quot; &quot;$(ProjectDir)..\&quot; &quot;$(ProjectDir)&quot; &quot;$(TargetDir)&quot;" />
</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 e PostBuild, quindi usando tali nomi è possibile modificare i comandi nell'IDE.
  • Le proprietà PreBuildEvent e PostBuildEvent 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.

Vedi anche