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

Проекты .NET Core и NET 5 и более поздних версий связаны с пакетом средств разработки программного обеспечения (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
Microsoft.NET.Sdk.WindowsDesktop Пакет SDK для классических приложений .NET, включающий Windows Forms (WinForms) и Windows Presentation Foundation (WPF).* https://github.com/dotnet/winforms и https://github.com/dotnet/wpf.

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

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

* Начиная с .NET 5, проекты Windows Forms и Windows Presentation Foundation (WPF) должны указывать пакет SDK для .NET (Microsoft.NET.Sdk) вместо Microsoft.NET.Sdk.WindowsDesktop. Если для параметра TargetFramework в таких проектах установить значение net5.0-windows, а для параметра UseWPF или UseWindowsForms — значение true, импорт пакета SDK для Windows Desktop будет выполняться автоматически. Если проект предназначен для .NET 5 или более поздней версии и в нем указан пакет SDK Microsoft.NET.Sdk.WindowsDesktop, при сборке отобразится предупреждение NETSDK1137.

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

В основе проектов .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=netcoreapp2.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 с примерно таким сообщением:

Включены дублирующиеся элементы "Compile". The .NET SDK includes 'Compile' items from your project directory by default. You can either remove these items from your project file, or set the 'EnableDefaultCompileItems' property to 'false' if you want to explicitly include them in your project file. (Включены повторяющиеся элементы Compile. По умолчанию пакет SDK для .NET включает элементы Compile из каталога проекта. Можно удалить эти элементы из файла проекта или задать для свойства EnableDefaultCompileItems значение false, чтобы явно включить их в файл проекта).

Включены дублирующиеся элементы "EmbeddedResource". The .NET SDK includes 'EmbeddedResource' items from your project directory by default. You can either remove these items from your project file, or set the 'EnableDefaultEmbeddedResourceItems' property to 'false' if you want to explicitly include them in your project file. (Включены повторяющиеся элементы Compile. По умолчанию пакет SDK для .NET включает элементы Compile из каталога проекта. Можно удалить эти элементы из файла проекта или задать для свойства EnableDefaultCompileItems значение false, чтобы явно включить их в файл проекта).

Чтобы устранить такую проблему, выполните любое из следующих действий:

  • Удалите явно заданные элементы Compile, EmbeddedResource или None, которые совпадают с неявно заданными параметрами из предыдущей таблицы.

  • Присвойте свойству EnableDefaultItems значение false, чтобы отключить все неявные включения файлов:

    <PropertyGroup>
      <EnableDefaultItems>false</EnableDefaultItems>
    </PropertyGroup>
    

    Если вы хотите указать файлы, которые нужно публиковать вместе с приложением, для этого можно по-прежнему использовать привычные механизмы MSBuild (например, элемент Content).

  • Выборочно отключите только стандартные маски Compile, EmbeddedResource или None, присвоив свойствам EnableDefaultCompileItems, EnableDefaultEmbeddedResourceItems или EnableDefaultNoneItems значение false:

    <PropertyGroup>
      <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
      <EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
      <EnableDefaultNoneItems>false</EnableDefaultNoneItems>
    </PropertyGroup>
    

    Если вы отключаете Compile только глобы, Обозреватель решений в Visual Studio по-прежнему отображаются элементы *.cs в составе проекта, включенные в качестве None элементов. Чтобы отключить неявную стандартную маску None, задайте свойству EnableDefaultNoneItems значение false.

Неявные директивы 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 Core 1.0–2.2 или .NET Standard 1.0–2.0 пакет SDK для .NET добавляет неявные ссылки на определенные метапакеты. Метапакет — это пакет на основе платформы, который состоит только из зависимостей от других пакетов. Теперь неявные ссылки на метапакеты указываются в зависимости от целевой платформы, указанной в свойстве TargetFramework или TargetFrameworks файла проекта.

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<PropertyGroup>
  <TargetFrameworks>netcoreapp2.1;net462</TargetFrameworks>
</PropertyGroup>

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

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

  • При использовании .NET Framework, .NET Core 1.0–2.2 или .NET Standard 1.0–2.0 не добавляйте явную ссылку на метапакеты Microsoft.NETCore.App или NETStandard.Library через элемент <PackageReference> в файле проекта. Для проектов .NET Core 1.0–2.2 и .NET Standard 1.0–2.0 ссылка на эти метапакеты неявно присутствует. Если при использовании проектов .NET Framework и пакета NuGet на основе .NET Standard требуется любая версия NETStandard.Library, NuGet автоматически устанавливает ее.
  • Если при использовании .NET Core 1.0–2.2 нужна определенная версия среды выполнения, вместо ссылки на метапакет следует использовать свойство <RuntimeFrameworkVersion> в проекте (например, 1.0.4). Например, может потребоваться специальная версия LTS среды выполнения 1.0.0, если вы используете автономные развертывания.
  • Если при использовании .NET Standard 1.0–2.0 вам нужна конкретная версия метапакета NETStandard.Library, можно использовать свойство <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.

См. также