.NET 프로젝트 SDK

.NET Core 및 .NET 5 이상 프로젝트는 SDK(소프트웨어 개발 키트)와 연결됩니다. 각 ‘프로젝트 SDK’는 코드를 컴파일, 압축 및 게시해야 하는 MSBuild 대상 및 관련 작업 집합입니다. 프로젝트 SDK를 참조하는 프로젝트를 ‘SDK 스타일 프로젝트’라고도 합니다.

사용 가능한 SDK

다음 SDK를 사용할 수 있습니다.

ID 설명 리포지토리
Microsoft.NET.Sdk .NET SDK https://github.com/dotnet/sdk
Microsoft.NET.Sdk.Web .NET 웹 SDK https://github.com/dotnet/sdk
Microsoft.NET.Sdk.BlazorWebAssembly .NET Blazor WebAssembly SDK https://github.com/dotnet/aspnetcore
Microsoft.NET.Sdk.Razor .NET Razor SDK https://github.com/dotnet/aspnetcore
Microsoft.NET.Sdk.Worker .NET Worker Service SDK
Microsoft.NET.Sdk.WindowsDesktop WinForms(Windows Forms) 및 WPF(Windows Presentation Foundation)가 포함된 .NET 데스크톱 SDK.* https://github.com/dotnet/winformshttps://github.com/dotnet/wpf

.NET SDK는 .NET용 기본 SDK입니다. 다른 SDK는 .NET SDK를 참조하며 다른 SDK와 연결된 프로젝트는 모든 .NET SDK 속성을 사용할 수 있습니다. 예를 들어 웹 SDK는 .NET SDK 및 Razor SDK에 종속됩니다.

NuGet을 통해 배포할 수 있는 고유한 SDK를 작성할 수도 있습니다.

* .NET 5부터 Windows Forms 및 WPF(Windows Presentation Foundation) 프로젝트는 Microsoft.NET.Sdk.WindowsDesktop 대신 .NET SDK(Microsoft.NET.Sdk)를 지정해야 합니다. 이러한 프로젝트의 경우 TargetFrameworknet5.0-windows로 설정하고 UseWPF 또는 UseWindowsFormstrue로 설정하면 Windows 데스크톱 SDK를 자동으로 가져옵니다. 프로젝트가 .NET 5 이상을 대상으로 하고 Microsoft.NET.Sdk.WindowsDesktop SDK를 지정하는 경우 빌드 경고 NETSDK1137이 발생합니다.

프로젝트 파일

.NET 프로젝트는 MSBuild 형식을 기반으로 합니다. .csproj(C# 프로젝트) 및 .fsproj(F# 프로젝트) 같은 확장명을 가진 프로젝트 파일은 XML 형식입니다. MSBuild 프로젝트 파일의 루트 요소는 Project 요소입니다. Project 요소에는 사용할 SDK(및 버전)를 지정하는 선택적 Sdk 특성이 있습니다. .NET 도구를 사용하고 코드를 빌드하려면 Sdk 특성을 사용 가능한 SDK 표의 ID 중 하나로 설정합니다.

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

NuGet에서 제공되는 SDK를 지정하려면 이름 끝에 버전을 포함하거나 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.propsSdk.targets 파일은 %ProgramFiles%\dotnet\sdk\[버전]\Sdks\Microsoft.NET.Sdk\Sdk 폴더에 있습니다.

프로젝트 파일 전처리

dotnet msbuild -preprocess 명령을 사용하여 SDK 및 해당 대상이 포함된 후 MSBuild에서 보는 것처럼 완전히 확장된 프로젝트를 볼 수 있습니다. dotnet msbuild 명령의 preprocess 스위치는 가져온 파일, 해당 소스 및 실제로 프로젝트를 빌드하지 않는 빌드에 대한 기여를 표시합니다.

프로젝트에 대상 프레임워크가 여러 개 있는 경우 명령의 결과는 대상을 MSBuild 속성으로 지정하여 프레임워크 하나에만 초점을 맞춥니다. 예시:

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

기본 포함 및 제외

Compile 항목, 포함된 리소스, None 항목의 기본 포함 및 제외는 SDK에서 정의됩니다. SDK가 아닌 .NET Framework 프로젝트와 달리 기본값은 대부분의 일반적인 사용 사례를 처리하므로 프로젝트 파일에서 해당 항목을 지정할 필요가 없습니다. 따라서 프로젝트 파일이 크기가 줄어들고 이해하기가 더 쉬워지며 필요에 따라 수동으로 편집할 수 있습니다.

다음 표에는 .NET SDK에 포함되거나 제외되는 요소 및 GLOB가 나와 있습니다.

요소 GLOB 포함 GLOB 제외 GLOB 제거
Compile **/*.cs(또는 기타 언어 확장) **/*.user; **/*.*proj; **/*.sln; **/*.vssscc 해당 없음
EmbeddedResource **/*.resx **/*.user; **/*.*proj; **/*.sln; **/*.vssscc 해당 없음
None **/* **/*.user; **/*.*proj; **/*.sln; **/*.vssscc **/*.cs; **/*.resx

참고 항목

$(BaseOutputPath)$(BaseIntermediateOutputPath) MSBuild 속성으로 나타내는 ./bin./obj 폴더는 기본적으로 GLOB에서 제외됩니다. 제외는 DefaultItemExcludes 속성으로 표시됩니다.

.NET 데스크톱 SDK에는 WPF에 대한 더 많은 포함 및 제외가 있습니다. 자세한 내용은 WPF 기본 포함 및 제외를 참조하세요.

빌드 오류

프로젝트 파일에서 이러한 항목을 명시적으로 정의하는 경우 다음과 비슷한 "NETSDK1022" 빌드 오류가 발생할 수 있습니다.

중복 ‘Compile’ 항목이 포함되었습니다. .NET SDK에는 기본적으로 프로젝트 디렉터리의 ‘Compile’ 항목이 포함됩니다. 프로젝트 파일에서 해당 항목을 제거하거나, 프로젝트 파일에서 해당 항목을 명시적으로 포함하려면 ‘EnableDefaultCompileItems’ 속성을 ‘false’로 설정하면 됩니다.

중복 ‘EmbeddedResource’ 항목이 포함되었습니다. .NET SDK에는 기본적으로 프로젝트 디렉터리의 ‘EmbeddedResource’ 항목이 포함됩니다. 프로젝트 파일에서 해당 항목을 제거하거나, 프로젝트 파일에서 해당 항목을 명시적으로 포함하려면 ‘EnableDefaultEmbeddedResourceItems’ 속성을 ‘false’로 설정하면 됩니다.

오류를 해결하려면 다음 중 하나를 수행합니다.

  • 앞의 표에 나열된 암시적 Compile, EmbeddedResource 또는 None 항목과 일치하는 항목을 제거합니다.

  • 모든 암시적 파일 포함을 사용하지 않으려면 EnableDefaultItems 속성false로 설정합니다.

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

    앱과 함께 게시할 파일을 지정하려는 경우 해당 항목(예: Content 요소)에 알려진 MSBuild 메커니즘을 계속 사용할 수 있습니다.

  • EnableDefaultCompileItems, EnableDefaultEmbeddedResourceItems 또는 EnableDefaultNoneItems 속성을 false로 설정하여 Compile, EmbeddedResource 또는 None GLOB를 선택적으로 사용하지 않도록 설정합니다.

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

    Compile GLOB만 사용하지 않도록 설정하는 경우 Visual Studio의 솔루션 탐색기는 *.cs 항목을 None 항목으로 포함된 프로젝트의 일부로 계속 표시합니다. 암시적 None GLOB를 사용하지 않도록 설정하려면 EnableDefaultNoneItemsfalse로 설정합니다.

암시적 using 지시문

.NET 6부터 암시적 global using 지시문이 새 C# 프로젝트에 추가됩니다. 즉, 정규화된 이름을 지정하거나 using 지시문을 수동으로 추가하지 않고도 이러한 네임스페이스에 정의된 형식을 사용할 수 있습니다. 암시적 측면은 global using 지시문이 프로젝트의 obj 디렉터리 내 생성된 파일에 추가된다는 사실을 의미합니다.

다음 SDK 중 하나를 사용하는 프로젝트에 암시적 global using 지시문이 추가됩니다.

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

프로젝트의 SDK를 기반으로 하는 기본 네임스페이스 집합의 각 네임스페이스에 global using 지시문이 추가됩니다. 이러한 기본 네임스페이스는 다음 표에 표시됩니다.

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 제거

이 기능을 사용하지 않도록 설정하거나 기존 C# 프로젝트에서 암시적 global using 지시문을 사용하도록 설정하려는 경우 ImplicitUsings MSBuild 속성을 통해 이 작업을 수행할 수 있습니다.

프로젝트 파일에 Using 항목(Visual Basic 프로젝트의 경우 Import 항목)을 추가하여 추가 암시적 global using 지시문을 지정할 수 있습니다. 예를 들면 다음과 같습니다.

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

암시적 패키지 참조

.NET Core 1.0 ~ 2.2 또는 .NET Standard 1.0 ~ 2.0을 대상으로 지정하는 경우 .NET SDK는 특정 메타패키지에 대한 암시적 참조를 추가합니다. 메타패키지는 다른 패키지에 대한 종속성으로만 구성된 프레임워크 기반 패키지입니다. 메타패키지는 프로젝트 파일의 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을 대상으로 하는 경우 프로젝트 파일의 <PackageReference> 항목을 통해 Microsoft.NETCore.App 또는 NETStandard.Library 메타패키지에 대한 명시적 참조를 추가하지 마세요. .NET Core 1.0~2.2 및 .NET Standard 1.0~2.0 프로젝트의 경우 이러한 메타패키지를 암시적으로 참조합니다. .NET Framework 프로젝트의 경우 .NET Standard 기반 NuGet 패키지를 사용할 때 모든 버전의 NETStandard.Library가 필요하면 NuGet은 자동으로 해당 버전을 설치합니다.
  • .NET Core 1.0 ~ 2.2을 대상으로 할 때 특정 버전의 런타임이 필요하면 메타패키지를 참조하는 대신 프로젝트의 <RuntimeFrameworkVersion> 속성(예: 1.0.4)을 사용해야 합니다. 예를 들어 자체 포함 배포를 사용하는 경우 1.0.0 LTS 런타임의 특정 패치 버전이 필요할 수 있습니다.
  • .NET Standard 1.0 ~ 2.0을 대상으로 할 때 특정 버전의 NETStandard.Library 메타패키지가 필요하면 <NetStandardImplicitPackageVersion> 속성을 사용하고 필요한 버전을 설정할 수 있습니다.

빌드 이벤트

SDK 스타일 프로젝트에서 PreBuild 또는 PostBuild라는 MSBuild 대상을 사용하고 PreBuild에 대해 BeforeTargets 속성을 설정하거나 PostBuild에 대해 AfterTargets 속성을 설정합니다.

<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 IDE는 PreBuildPostBuild 대상을 인식하므로 해당 이름을 사용하여 IDE에서 명령을 편집할 수 있습니다.
  • $(ProjectDir) 같은 매크로는 확인되지 않으므로 SDK 스타일 프로젝트에서는 PreBuildEventPostBuildEvent 속성을 권장하지 않습니다. 예를 들어, 다음 코드는 지원되지 않습니다.
<PropertyGroup>
  <PreBuildEvent>"$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)"</PreBuildEvent>
</PropertyGroup>

빌드 사용자 지정

다양한 방법으로 빌드를 사용자 지정할 수 있습니다. msbuild 또는 dotnet 명령에 인수로 전달하여 속성을 재정의할 수 있습니다. 또한 프로젝트 파일 또는 Directory.Build.props 파일에 속성을 추가할 수 있습니다. .NET 프로젝트의 유용한 속성 목록을 보려면 .NET SDK 프로젝트용 MSBuild 참조를 참조하세요.

명령줄에서 새 Directory.Build.props 파일을 만드는 쉬운 방법은 리포지토리의 루트에 있는 dotnet new buildprops 명령을 사용하는 것입니다.

사용자 지정 대상

.NET 프로젝트는 패키지를 사용하는 프로젝트에서 사용할 사용자 지정 MSBuild 대상 및 속성을 패키지할 수 있습니다. 다음을 수행하려는 경우 이 유형의 확장성을 사용합니다.

  • 빌드 프로세스를 확장합니다.
  • 생성된 파일과 같은 빌드 프로세스의 아티팩트에 액세스합니다.
  • 빌드를 호출하는 데 사용된 구성을 검사합니다.

프로젝트의 build 폴더에 <package_id>.targets 또는 <package_id>.props(예: Contoso.Utility.UsefulStuff.targets) 형식의 파일을 배치하여 사용자 지정 빌드 대상 또는 속성을 추가합니다.

다음 XML은 dotnet pack 명령에 패키지할 항목을 알리는 .csproj 파일의 코드 조각입니다. <ItemGroup Label="dotnet pack instructions"> 요소는 패키지 내부 build 폴더에 대상 파일을 배치합니다. <Target Name="CollectRuntimeOutputs" BeforeTargets="_GetPackageFiles"> 요소는 build 폴더에 어셈블리 및 .json 파일을 배치합니다.

<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 호출로 변환합니다. 이러한 종류의 시너지 효과는 dotnet-packer 프로젝트의 MVP Summit 2016 Hackathon 샘플 리포지토리에서 확인할 수 있습니다.

참고 항목