Пакеты SDK для проектов .NET

Современные проекты .NET связаны с пакетом средств разработки программного обеспечения (SDK). Каждый пакет SDK для проекта является набором целевых объектов MSBuild и связанных задач, которые отвечают за компиляцию, упаковку и публикацию кода. Проект, который ссылается на пакет SDK для проекта, иногда называется проектом в стиле пакета SDK.

Доступные пакеты SDK

Доступны следующие пакеты SDK:

Идентификатор Description Репозиторий
Microsoft.NET.Sdk .NET SDK https://github.com/dotnet/sdk
Microsoft.NET.Sdk.Web Веб-пакет SDK для .NET https://github.com/dotnet/sdk
Microsoft.NET.Sdk.BlazorWebAssembly BlazorПакет SDK WebAssembly для .NET https://github.com/dotnet/aspnetcore
Microsoft.NET.Sdk.Razor Пакет SDK Razor для .NET https://github.com/dotnet/aspnetcore
Microsoft.NET.Sdk.Worker Пакет SDK для рабочей службы .NET

Пакет SDK для .NET является базовым пакетом SDK для .NET. Другие пакеты SDK ссылаются на пакет SDK для .NET, а проекты, связанные с другими пакетами SDK, имеют все доступные им свойства пакета SDK для .NET. Например, веб-пакет SDK зависит от пакета SDK для .NET и пакета SDK для Razor.

Можно также создать собственный пакет SDK и распространять его с помощью NuGet.

Для проектов Windows Forms и Windows Presentation Foundation (WPF) необходимо указать пакет SDK для .NET (Microsoft.NET.Sdk) и задать некоторые дополнительные свойства в файле проекта. Дополнительные сведения см. в разделе "Включение пакета SDK для классических приложений .NET".

Файлы проекта

В основе проектов .NET лежит формат MSBuild. Файлы проекта с такими расширениями, как CPROJ для проектов C# и FPROJ для проектов F#, имеют формат XML. Корневым элементом файла проекта MSBuild является элемент Project. Элемент Project имеет необязательный атрибут Sdk, указывающий, какой пакет SDK (и версию) следует использовать. Чтобы использовать средства .NET и выполнить сборку кода, задайте в качестве значения атрибута Sdk один из идентификаторов, указанных в таблицеДоступные пакеты SDK.

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

Чтобы указать пакет SDK, который содержится в NuGet, добавьте версию в конец имени или укажите имя и версию в файле global.json.

<Project Sdk="MSBuild.Sdk.Extras/2.0.54">
  ...
</Project>

Другим способом указать пакет SDK является элемент верхнего уровня Sdk :

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

Указание пакета SDK одним из этих способов значительно упрощает файлы проекта для .NET. На этапе оценки проекта MSBuild добавляет неявные директивы импорта для Sdk.props в начале и для Sdk.targets в конце файла проекта.

<Project>
  <!-- Implicit top import -->
  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
  ...
  <!-- Implicit bottom import -->
  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>

Совет

На компьютере с Windows файлы Sdk.props и Sdk.targets можно найти в папке %ProgramFiles%\dotnet\sdk\[version]\Sdk\Microsoft.NET.Sdk\Sdk\Sdk .

Предварительная обработка файла проекта

Увидеть полностью развернутый проект так, как он отображается в MSBuild, можно после включения пакета SDK и его целевых объектов с помощью команды dotnet msbuild -preprocess. Включите параметр preprocess в команду dotnet msbuild, чтобы просмотреть сведения об импортированных файлах, их источниках, вкладе в сборку без фактического создания проекта.

Если проект имеет несколько требуемых версий .NET Framework, результаты выполнения команды должны касаться только одной из них. Эту версию следует указать в качестве свойства MSBuild. Например:

dotnet msbuild -property:TargetFramework=net8.0 -preprocess:output.xml

Включения и исключения по умолчанию

В пакете SDK определены стандартные включения и исключения для элементов Compile, внедренных ресурсов и элементов None. В отличие от проектов .NET Framework без пакетов SDK в файле проекта не нужно указывать эти элементы, так как для наиболее распространенных вариантов использования действуют значения по умолчанию. Такой подход позволяет уменьшить файлы проекта и без труда понимать их, а при необходимости даже вносить правки вручную.

В следующей таблице показано, какие элементы и стандартные маски включены в пакет SDK для .NET и исключены из него:

Элемент Стандартная маска включения Стандартная маска исключения Стандартная маска удаления
Compile **/*.cs (или другие расширения языка) **/*.Пользователя; **/*.*Proj; **/*.Sln; **/*.Vssscc Н/П
EmbeddedResource **/*.Resx **/*.Пользователя; **/*.*Proj; **/*.Sln; **/*.Vssscc Н/П
None **/* **/*.Пользователя; **/*.*Proj; **/*.Sln; **/*.Vssscc **/*.Cs; **/*.Resx

Примечание.

Папки ./bin и ./obj, которые представлены свойствами MSBuild $(BaseOutputPath) и $(BaseIntermediateOutputPath), исключаются из стандартных масок исключения по умолчанию. Исключения представлены свойством DefaultItemExcludes.

Пакет SDK для классических приложений .NET содержит дополнительные компоненты и исключает их для WPF. Дополнительные сведения см. в разделе Включения и исключения для WPF.

Если вы явно определяете любой из этих элементов в файле проекта, скорее всего, вы получите ошибку сборки NETSDK1022 . Сведения об устранении ошибки см. в разделе NETSDK1022: были включены повторяющиеся элементы.

Неявные директивы using

Начиная с .NET 6 неявные директивы global using добавляются в новые проекты C#. Это означает, что вы можете использовать определенные в этих пространствах имен типы без указания полных имен или добавления директивы using вручную. Термин неявный здесь обозначает, что директивы global using добавляются в созданный файл в каталоге проекта obj.

Неявные директивы global using добавляются для проектов, которые используют один из следующих пакетов SDK:

  • Microsoft.NET.Sdk
  • Microsoft.NET.Sdk.Web
  • Microsoft.NET.Sdk.Worker
  • Microsoft.NET.Sdk.WindowsDesktop

Директива global using добавляется для каждого пространства имен в наборе пространств имен по умолчанию, основанных на пакете SDK проекта. Эти пространства имен по умолчанию показаны в следующей таблице.

SDK Пространства имен по умолчанию
Microsoft.NET.Sdk System
System.Collections.Generic
System.IO
System.Linq
System.Net.Http
System.Threading
System.Threading.Tasks
Microsoft.NET.Sdk.Web Пространства имен 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 Пространства имен Microsoft.NET.Sdk
Microsoft.Extensions.Configuration
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Hosting
Microsoft.Extensions.Logging
Microsoft.NET.Sdk.WindowsDesktop (Windows Forms) Пространства имен Microsoft.NET.Sdk
System.Drawing
System.Windows.Forms
Microsoft.NET.Sdk.WindowsDesktop (WPF) Пространства имен Microsoft.NET.Sdk
System.IO удалено
System.Net.Http удалено

Если вы хотите отключить эту возможность или включить неявные директивы global using для существующего проекта C#, это можно сделать с помощью свойства MSBuild ImplicitUsings.

Вы можете указать дополнительные неявные директивы global using, добавив элементы Using (или элементы Import для проектов Visual Basic) в файл проекта, например так:

<ItemGroup>
  <Using Include="System.IO.Pipes" />
</ItemGroup>

Неявные ссылки на пакет

Когда проект предназначен для .NET Standard 1.0-2.0, пакет SDK для .NET добавляет неявные ссылки на определенные метапакеты. Метапакет — это пакет на основе платформы, который состоит только из зависимостей от других пакетов. Метапакеты неявно ссылаются на целевые платформы, указанные в свойстве TargetFramework или TargetFrameworks (plural) файла проекта.

<PropertyGroup>
  <TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
  <TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
</PropertyGroup>

При необходимости можно отключить неявные ссылки на пакеты с помощью свойства DisableImplicitFrameworkReferences и добавить явные ссылки только на необходимые платформы или пакеты.

Рекомендации.

  • Если вы используете платформа .NET Framework или .NET Standard 1.0-2.0, не добавляйте явную ссылку на NETStandard.Library метапакеты через <PackageReference> элемент в файле проекта. Для проектов .NET Standard 1.0-2.0 эти метапакеты неявно ссылаются. Если при использовании проектов .NET Framework и пакета NuGet на основе .NET Standard требуется любая версия NETStandard.Library, NuGet автоматически устанавливает ее.
  • Если вам нужна определенная версия метапакета NETStandard.Library для .NET Standard 1.0-2.0, можно использовать <NetStandardImplicitPackageVersion> свойство и задать нужную версию.

События сборки

Для проектов в стиле пакета SDK используйте целевой объект MSBuild с именем PreBuild или PostBuild и задайте свойство BeforeTargets для PreBuild или свойство AfterTargets для 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>

Примечание.

  • Для целевых объектов MSBuild можно использовать любые имена. Однако интегрированная среда разработки Visual Studio распознает целевые объекты PreBuild и PostBuild, поэтому с помощью этих имен можно изменять команды в интегрированной среде разработки.
  • Свойства PreBuildEvent и PostBuildEvent не рекомендуется использовать в проектах в стиле пакета SDK, поскольку такие макросы, как $(ProjectDir), не разрешены. Например, приведенный ниже код не поддерживается.
<PropertyGroup>
  <PreBuildEvent>"$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)"</PreBuildEvent>
</PropertyGroup>

Настройка сборки

Существует несколько способов настройки сборки. Может потребоваться переопределить свойство, передав его в качестве аргумента команде msbuild или dotnet . Вы также можете добавить свойство в файл проекта или в файл Directory.Build.props. Список полезных свойств для проектов .NET см. в статье Справочник по MSBuild для проектов пакета SDK для .NET.

Совет

Простой способ создать файл Directory.Build.props из командной строки — использовать команду dotnet new buildprops в корневом каталоге репозитория.

Пользовательские целевые объекты

В проектах .NET доступна возможность упаковки пользовательских целевых объектов MSBuild и свойств для использования в проектах, применяющих этот пакет. Используйте этот тип расширяемости, если нужно выполнить следующие задачи:

  • расширить процесс сборки;
  • получить доступ к артефактам процесса сборки, таким как созданные файлы;
  • проверить конфигурацию, с которой была запущена сборка.

Чтобы добавить пользовательские целевые объекты или свойства сборки, нужно поместить файлы в форме <package_id>.targets или <package_id>.props (например, Contoso.Utility.UsefulStuff.targets) в папку build проекта.

Следующий XML-код является фрагментом из файла CPROJ, который указывает команде dotnet pack, что именно нужно упаковать. Элемент <ItemGroup Label="dotnet pack instructions"> помещает файлы целевых объектов в папку build в пакете. Элемент <Target Name="CollectRuntimeOutputs" BeforeTargets="_GetPackageFiles"> помещает сборки и файлы JSON в папку 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>

Чтобы использовать пользовательский целевой объект в проекте, добавьте элемент PackageReference, указывающий на пакет и его версию. В отличие от средств пакет пользовательских целевых объектов входит в замыкание зависимостей исходного проекта.

Вы можете настроить способ использования пользовательского целевого объекта. Так как это целевой объект MSBuild, он может зависеть от заданного целевого объекта, запускаться после другого целевого объекта или быть вызван вручную с помощью команды dotnet msbuild -t:<target-name>. Однако для удобства пользователей можно объединить средства для отдельных проектов и пользовательские целевые объекты. В этом сценарии средство для отдельного проекта принимает необходимые параметры и преобразует их в требуемый вызов dotnet msbuild, который выполняет целевой объект. Пример подобного типа синергии можно увидеть в репозитории примеров хакатона MVP Summit 2016 в проекте dotnet-packer.

См. также