Пакеты SDK для проектов .NET
Современные проекты .NET связаны с пакетом средств разработки программного обеспечения проекта (SDK). Каждый пакет SDK для проекта является набором целевых объектов MSBuild и связанных задач, которые отвечают за компиляцию, упаковку и публикацию кода. Проект, который ссылается на пакет SDK для проекта, иногда называется проектом в стиле пакета SDK.
Доступные пакеты SDK
Доступны следующие пакеты SDK:
ID | 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.Razor |
Пакет SDK Razor для .NET | https://github.com/dotnet/aspnetcore |
Microsoft.NET.Sdk.BlazorWebAssembly |
BlazorПакет SDK WebAssembly для .NET | https://github.com/dotnet/aspnetcore |
Microsoft.NET.Sdk.Worker |
Пакет SDK для рабочей службы .NET | |
Aspire.AppHost.Sdk |
Пакет SDK для .NET Aspire | https://github.com/dotnet/aspire |
MSTest.Sdk |
Пакет SDK MSTest | https://github.com/microsoft/testfx |
Пакет 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>
Начиная с .NET Aspire 9, предыдущий пример может использовать пакет SDK для .NET Aspire.
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0-rc.1.24511.1" />
<!-- Omitted for brevity... -->
</Project>
Дополнительные сведения см. в статье о средстве и настройке .NET Aspire.
Чтобы указать пакет 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=""$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)"" />
</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
.