ASP.NET Core 2.2에서 3.0으로 마이그레이션

작성자: Scott AddieRick Anderson

이 문서에서는 기존 ASP.NET Core 2.2 프로젝트를 ASP.NET Core 3.0으로 업데이트하는 방법을 설명합니다. 새 ASP.NET Core 3.0 프로젝트를 만들면 다음과 같은 작업을 수행할 수 있습니다.

  • ASP.NET Core 2.2 코드와 비교합니다.
  • 관련 변경 내용을 ASP.NET Core 3.0 프로젝트에 복사합니다.

필수 조건

에서 .NET Core SDK 버전 업데이트 global.json

솔루션이 특정 .NET Core SDK 버전을 대상으로 하는 파일을 사용하는 global.json 경우 해당 version 속성을 컴퓨터에 설치된 3.0 버전으로 업데이트합니다.

{
  "sdk": {
    "version": "3.0.100"
  }
}

프로젝트 파일 업데이트

대상 프레임워크 업데이트

ASP.NET Core 3.0 이상은 .NET Core에서만 실행됩니다. TFM(대상 프레임워크 모니커)netcoreapp3.0으로 설정합니다.

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

</Project>

사용되지 않는 패키지 참조 제거

많은 수의 NuGet 패키지가 ASP.NET Core 3.0에 대해 생성되지 않습니다. 프로젝트 파일에서 이러한 패키지 참조를 제거해야 합니다. ASP.NET Core 2.2 웹앱의 다음 프로젝트 파일을 살펴보겠습니다.

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

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App"/>
    <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
  </ItemGroup>

</Project>

ASP.NET Core 3.0에 대해 업데이트된 프로젝트 파일:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

</Project>

업데이트된 ASP.NET Core 3.0 프로젝트 파일:

  • <PropertyGroup>에서

    • TFM을 netcoreapp3.0으로 업데이트합니다.
    • <AspNetCoreHostingModel> 요소를 제거합니다. 자세한 내용은 본 문서의 In-Process 호스팅 모델을 참조하세요.
  • <ItemGroup>에서

    • Microsoft.AspNetCore.App이 제거됩니다. 자세한 내용은 본 문서의 프레임워크 참조를 참조하세요.
    • Microsoft.AspNetCore.Razor.Design이 제거되고 후속 패키지 목록에서 더 이상 생성되지 않습니다.

더 이상 생성되지 않는 패키지의 전체 목록을 보려면 다음 확장 목록을 선택하세요.

더 이상 생성되지 않는 패키지 목록을 확장하려면 클릭하세요
  • Microsoft.AspNetCore
  • Microsoft.AspNetCore.All
  • Microsoft.AspNetCore.App
  • Microsoft.AspNetCore.Antiforgery
  • Microsoft.AspNetCore.Authentication
  • Microsoft.AspNetCore.Authentication.Abstractions
  • Microsoft.AspNetCore.Authentication.Cookies
  • Microsoft.AspNetCore.Authentication.Core
  • Microsoft.AspNetCore.Authentication.OAuth
  • Microsoft.AspNetCore.Authorization.Policy
  • Microsoft.AspNetCore.CookiePolicy
  • Microsoft.AspNetCore.Cors
  • Microsoft.AspNetCore.Diagnostics
  • Microsoft.AspNetCore.Diagnostics.HealthChecks
  • Microsoft.AspNetCore.HostFiltering
  • Microsoft.AspNetCore.Hosting
  • Microsoft.AspNetCore.Hosting.Abstractions
  • Microsoft.AspNetCore.Hosting.Server.Abstractions
  • Microsoft.AspNetCore.Http
  • Microsoft.AspNetCore.Http.Abstractions
  • Microsoft.AspNetCore.Http.Connections
  • Microsoft.AspNetCore.Http.Extensions
  • Microsoft.AspNetCore.HttpOverrides
  • Microsoft.AspNetCore.HttpsPolicy
  • Microsoft.AspNetCore.Identity
  • Microsoft.AspNetCore.Localization
  • Microsoft.AspNetCore.Localization.Routing
  • Microsoft.AspNetCore.Mvc
  • Microsoft.AspNetCore.Mvc.Abstractions
  • Microsoft.AspNetCore.Mvc.Analyzers
  • Microsoft.AspNetCore.Mvc.ApiExplorer
  • Microsoft.AspNetCore.Mvc.Api.Analyzers
  • Microsoft.AspNetCore.Mvc.Core
  • Microsoft.AspNetCore.Mvc.Cors
  • Microsoft.AspNetCore.Mvc.DataAnnotations
  • Microsoft.AspNetCore.Mvc.Formatters.Json
  • Microsoft.AspNetCore.Mvc.Formatters.Xml
  • Microsoft.AspNetCore.Mvc.Localization
  • Microsoft.AspNetCore.Mvc.Razor
  • Microsoft.AspNetCore.Mvc.Razor.ViewCompilation
  • Microsoft.AspNetCore.Mvc.RazorPages
  • Microsoft.AspNetCore.Mvc.TagHelpers
  • Microsoft.AspNetCore.Mvc.ViewFeatures
  • Microsoft.AspNetCore.Razor
  • Microsoft.AspNetCore.Razor.Runtime
  • Microsoft.AspNetCore.Razor.Design
  • Microsoft.AspNetCore.ResponseCaching
  • Microsoft.AspNetCore.ResponseCaching.Abstractions
  • Microsoft.AspNetCore.ResponseCompression
  • Microsoft.AspNetCore.Rewrite
  • Microsoft.AspNetCore.Routing
  • Microsoft.AspNetCore.Routing.Abstractions
  • Microsoft.AspNetCore.Server.HttpSys
  • Microsoft.AspNetCore.Server.IIS
  • Microsoft.AspNetCore.Server.IISIntegration
  • Microsoft.AspNetCore.Server.Kestrel
  • Microsoft.AspNetCore.Server.Kestrel.Core
  • Microsoft.AspNetCore.Server.Kestrel.Https
  • Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions
  • Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets
  • Microsoft.AspNetCore.Session
  • Microsoft.AspNetCore.SignalR
  • Microsoft.AspNetCore.SignalR.Core
  • Microsoft.AspNetCore.StaticFiles
  • Microsoft.AspNetCore.WebSockets
  • Microsoft.AspNetCore.WebUtilities
  • Microsoft.Net.Http.Headers

호환성이 손상되는 변경 검토

호환성이 손상되는 변경 검토

프레임워크 참조

위에 나열된 패키지 중 하나를 통해 사용할 수 있었던 ASP.NET Core의 기능은 Microsoft.AspNetCore.App 공유 프레임워크의 일부로 사용할 수 있습니다. 공유 프레임워크는 머신에 설치된 어셈블리(.dll 파일) 세트이며 런타임 구성 요소 및 타기팅 팩을 포함합니다. 자세한 내용은 공유 프레임워크를 참조하세요.

  • Microsoft.NET.Sdk.Web SDK를 대상으로 하는 프로젝트는 Microsoft.AspNetCore.App 프레임워크를 암시적으로 참조합니다.

    이러한 프로젝트에는 추가 참조가 필요하지 않습니다.

    <Project Sdk="Microsoft.NET.Sdk.Web">
      <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
      </PropertyGroup>
        ...
    </Project>
    
  • Microsoft.NET.Sdk 또는 Microsoft.NET.Sdk.Razor SDK를 대상으로 하는 프로젝트는 Microsoft.AspNetCore.App에 명시적 FrameworkReference를 추가해야 합니다.

    <Project Sdk="Microsoft.NET.Sdk.Razor">
      <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
      </PropertyGroup>
    
      <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
      </ItemGroup>
        ...
    </Project>
    

Docker를 사용하는 프레임워크 종속 빌드

ASP.NET Core 공유 프레임워크에 종속되는 패키지를 사용하는 콘솔 앱의 프레임워크 종속 빌드는 다음과 같은 런타임 오류를 발생시킬 수 있습니다.

It was not possible to find any compatible framework version
The specified framework 'Microsoft.AspNetCore.App', version '3.0.0' was not found.
  - No frameworks were found.

Microsoft.AspNetCore.App 는 ASP.NET Core 런타임을 포함하는 공유 프레임워크이며 Docker 이미지에 dotnet/core/aspnet 만 존재합니다. 3.0 SDK는 공유 프레임워크에 있는 라이브러리의 중복 사본을 포함하지 않음으로써 ASP.NET Core를 사용하는 프레임워크 종속 빌드의 크기를 줄입니다. 이를 통해 최대 18MB를 절약할 수 있지만, ASP.NET Core 런타임이 앱을 실행할 수 있도록 설치되어 있어야 합니다.

앱에 ASP.NET Core 공유 프레임워크에 대한 종속성(직접 또는 간접)이 있는지 확인하려면 앱 빌드/게시 중에 생성된 파일을 검사 runtimeconfig.json 합니다. 다음 JSON 파일은 ASP.NET Core 공유 프레임워크에 대한 종속성을 보여 줍니다.

{
  "runtimeOptions": {
    "tfm": "netcoreapp3.0",
    "framework": {
      "name": "Microsoft.AspNetCore.App",
      "version": "3.0.0"
    },
    "configProperties": {
      "System.GC.Server": true
    }
  }
}

앱이 Docker를 사용하는 경우, ASP.NET Core 3.0을 포함하는 기본 이미지를 사용합니다. 예: docker pull mcr.microsoft.com/dotnet/core/aspnet:3.0.

제거된 어셈블리에 대해 패키지 참조 추가

ASP.NET Core 3.0은 기존에 Microsoft.AspNetCore.App 패키지 참조의 일부였던 일부 어셈블리를 제거합니다. 어느 어셈블리가 제거되었는지 시각화하여 보려면 두 공유 프레임워크 폴더를 비교합니다. 예를 들어, 버전 2.2.7과 3.0.0을 비교합니다.

shared framework assemblies comparison

제거된 어셈블리에서 제공하는 기능을 계속 사용하려면 대응하는 패키지의 3.0 버전을 참조합니다.

시작 변경

다음 이미지는 ASP.NET Core 2.2 Razor Pages 웹앱의 삭제된 줄과 변경된 줄을 보여 줍니다.

the deleted and changed lines in an ASP.NET Core 2.2 Razor Web app

위 이미지에서 삭제된 코드는 빨간색으로 표시되어 있습니다. 삭제된 코드는 파일 비교 전에 삭제된 cookie 옵션 코드를 표시하지 않습니다.

다음 이미지는 ASP.NET Core 3.0 Razor Pages 웹앱의 추가된 줄과 변경된 줄을 보여 줍니다.

the added and changed lines in an ASP.NET Core 3.0 Razor Web app

위 이미지에서 추가된 코드는 녹색으로 표시되어 있습니다. 다음과 같은 변경에 대한 자세한 내용은:

  • services.AddMvc에서 services.AddRazorPages로: 본 문서의 MVC 서비스 등록을 참조하세요.
  • CompatibilityVersion의 경우, ASP.NET Core MVC에 대한 호환성 버전을 참조하세요.
  • IHostingEnvironment에서 IWebHostEnvironment로: GitHub 공지를 참조하세요.
  • app.UseAuthorization 은 순서 권한 부여 미들웨어를 추가해야 한다는 사실을 보여 주기 위해 템플릿에 추가되었습니다. 앱이 권한 부여를 사용하지 않는 경우 app.UseAuthorization에 대한 호출을 제거할 수 있습니다.
  • app.UseEndpoints: 본 문서의 Razor Pages 또는 Startup.Configure 마이그레이션을 참조하세요.

분석기 지원

Microsoft.NET.Sdk.Web을 대상으로 하는 프로젝트는 기존에 Microsoft.AspNetCore.Mvc.Analyzers 패키지의 일부로 제공되었던 분석기를 명시적으로 참조합니다. 이러한 분석기를 참조하기 위해 추가 참조가 필요하지 않습니다.

앱이 기존에 Microsoft.AspNetCore.Mvc.Api.Analyzers 패키지의 일부로 제공되었던 API 분석기를 사용하는 경우, 프로젝트 파일이 .NET Core Web SDK의 일부로 제공되는 분석기를 참조하도록 편집하세요.

<Project Sdk="Microsoft.NET.Sdk.Web">
    <PropertyGroup>
        <TargetFramework>netcoreapp3.0</TargetFramework>
        <IncludeOpenAPIAnalyzers>true</IncludeOpenAPIAnalyzers>
    </PropertyGroup>

    ...
</Project>

Razor 클래스 라이브러리

MVC의 UI 구성 요소를 제공하는 Razor 클래스 라이브러리 프로젝트는 프로젝트 파일에서 AddRazorSupportForMvc 속성을 설정해야 합니다.

<PropertyGroup>
  <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
</PropertyGroup>

In-process 호스팅 모델

ASP.NET Core 3.0 이상에서, 프로젝트는 기본적으로 In-Process 호스팅 모델로 설정됩니다. <AspNetCoreHostingModel> 속성의 값이 InProcess인 경우 선택적으로 프로젝트 파일에서 이 속성을 제거할 수 있습니다.

Kestrel

구성

(에서 제공하는 웹 호스트 작성기)로 ConfigureWebHostDefaultsProgram.cs구성을 마이그레이션 Kestrel 합니다.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(serverOptions =>
            {
                // Set properties and call methods on options
            })
            .UseStartup<Startup>();
        });

앱이 ConfigureWebHostDefaults 대신 ConfigureWebHost를 사용하여 수동으로 호스트를 만드는 경우, 웹 호스트 작성기에서 UseKestrel을 호출합니다.

public static void Main(string[] args)
{
    var host = new HostBuilder()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .ConfigureWebHost(webBuilder =>
        {
            webBuilder.UseKestrel(serverOptions =>
            {
                // Set properties and call methods on options
            })
            .UseIISIntegration()
            .UseStartup<Startup>();
        })
        .Build();

    host.Run();
}

연결 미들웨어가 연결 어댑터를 대체함

Kestrel에서 연결 어댑터(Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal.IConnectionAdapter)가 제거되었습니다. 연결 어댑터를 연결 미들웨어로 대체하세요. 연결 미들웨어는 ASP.NET Core 파이프라인의 HTTP 미들웨어와 비슷하나 하위 수준 연결을 위한 것입니다. HTTPS 및 연결 로깅:

  • 연결 어댑터에서 연결 미들웨어로 이동되었습니다.
  • 이들 확장 메서드는 이전 버전의 ASP.NET Core에서와 동일하게 작동합니다.

자세한 내용은 Kestrel 문서의 ListenOptions.Protocols 섹션의 TlsFilterConnectionHandler 예제를 참조하세요.

전송 추상화가 이동되고 퍼블릭으로 변경됨

Kestrel 전송 계층이 Connections.Abstractions에서 공용 인터페이스로 공개되었습니다. 이 업데이트의 일환으로:

  • Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions 및 관련 형식이 제거되었습니다.
  • NoDelayListenOptions에서 전송 옵션으로 이동되었습니다.
  • Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal.SchedulingModeKestrelServerOptions에서 제거되었습니다.

자세한 내용은 다음 GitHub 리소스를 참조하세요.

Kestrel 요청 후행부 헤더

이전 버전의 ASP.NET Core를 대상으로 하는 앱의 경우:

  • Kestrel이 요청 헤더 컬렉션에 HTTP/1.1 청크 분할된 후행부 헤더를 추가합니다.
  • 후행부는 요청 본문을 끝까지 읽은 후에 사용 가능합니다.

이로 인해 헤더와 후행부 사이에 모호성이 발생하므로 3.0에서는 후행부가 새 컬렉션(RequestTrailerExtensions)으로 이동되었습니다.

HTTP/2 요청 후행부는:

  • ASP.NET Core 2.2에서 사용할 수 없습니다.
  • 3.0에서 RequestTrailerExtensions로 사용할 수 있습니다.

이러한 후행부에 액세스할 수 있도록 새 요청 확장 메서드가 제공됩니다. HTTP/1.1과 마찬가지로, 후행부는 요청 본문을 끝까지 읽은 후에 사용 가능합니다.

3.0 릴리스에서는 다음 RequestTrailerExtensions 메서드를 사용할 수 있습니다.

  • GetDeclaredTrailers: Gets 본문 다음에 어느 후행부가 나오는지 나열하는 요청 Trailer 헤더를 가져옵니다.
  • SupportsTrailers: 요청이 수신하는 후행부 헤더를 지원하는지 여부를 나타냅니다.
  • CheckTrailersAvailable: 요청이 후행부를 지원하는지와 후행부를 읽을 수 있는지 여부를 검사합니다. 이 검사는 읽을 후행부가 있다고 가정하지 않습니다. 이 메서드가 true를 반환하는 경우에도 읽을 후행부가 없을 수 있습니다.
  • GetTrailer: 응답으로부터 요청된 후행 헤더를 가져옵니다. GetTrailer를 호출하기 전에 SupportsTrailers를 검사하세요. 그러지 않으면 요청이 후행 헤더를 지원하지 않는 경우 NotSupportedException이 발생할 수 있습니다.

자세한 내용은 Put request trailers in a separate collection(요청 후행부를 별도의 컬렉션에 배치, dotnet/AspNetCore #10410)을 참조하세요.

AllowSynchronousIO가 비활성화됨

AllowSynchronousIOHttpRequest.Body.Read, HttpResponse.Body.Write, Stream.Flush와 같은 동기 I/O API를 사용 또는 사용하지 않음으로 설정합니다. 이러한 API는 스레드 고갈의 원인이 되며 앱 크래시로 이어질 수 있습니다. 3.0에서 AllowSynchronousIO는 기본적으로 사용하지 않도록 설정됩니다. 자세한 내용은 Kestrel 문서의 동기 I/O 섹션을 참조하세요.

동기 I/O가 필요한 경우, 사용 중인 서버에서 AllowSynchronousIO 옵션을 구성하여 사용하도록 설정할 수 있습니다(예: Kestrel을 사용하는 경우 ConfigureKestrel을 호출할 때). 서버(Kestrel, HttpSys, TestServer 등)는 다른 서버에 영향을 주지 않는 자체 AllowSynchronousIO 옵션을 갖습니다. 동기 I/O는 IHttpBodyControlFeature.AllowSynchronousIO 옵션을 사용하여 모든 서버에서 요청 건별로 사용하도록 설정할 수 있습니다.

var syncIOFeature = HttpContext.Features.Get<IHttpBodyControlFeature>();

if (syncIOFeature != null)
{
    syncIOFeature.AllowSynchronousIO = true;
}

TextWriter 구현이나 Dispose에서 동기 API를 호출하는 다른 스트림에 문제가 있는 경우 대신 새 DisposeAsync API를 호출하세요.

자세한 내용은 [Announcement] AllowSynchronousIO disabled in all servers([공지] 모든 서버에서 AllowSynchronousIO가 사용하지 않도록 설정됨, dotnet/AspNetCore #7644)를 참조하세요.

출력 포맷터 버퍼링

Newtonsoft.Json, XmlSerializerDataContractSerializer 기반 출력 포맷터는 동기 직렬화만 지원합니다. 이러한 포맷터가 서버의 AllowSynchronousIO 제한과 함께 작동하도록 하기 위해, MVC는 디스크에 쓰기 전에 이러한 포맷터의 출력을 버퍼링합니다. 버퍼링의 결과로 MVC는 이러한 포맷터를 사용하여 응답할 때 Content-Length 헤더를 포함하게 됩니다.

System.Text.Json은 비동기 직렬화를 지원하며, 따라서 System.Text.Json 기반 포맷터는 버퍼링하지 않습니다. 성능 향상을 위해 이 포맷터를 사용하는 방안을 고려하세요.

버퍼링을 사용하지 않도록 설정하려면 애플리케이션은 시작에서 SuppressOutputFormatterBuffering을 구성할 수 있습니다.

services.AddControllers(options => options.SuppressOutputFormatterBuffering = true)

AllowSynchronousIO도 구성하지 않을 경우 이로 인해 애플리케이션이 런타임 예외를 throw할 수 있습니다.

Microsoft.AspNetCore.Server.Kestrel.Https 어셈블리가 제거됨

ASP.NET Core 2.1에서 Microsoft.AspNetCore.Server.Kestrel.Https.dll의 콘텐츠가 Microsoft.AspNetCore.Server.Kestrel.Core.dll로 이동되었습니다. 이는 TypeForwardedTo 특성을 사용하는, 호환성을 손상하지 않는 업데이트입니다. 3.0에서는 빈 Microsoft.AspNetCore.Server.Kestrel.Https.dll 어셈블리와 NuGet 패키지가 제거되었습니다.

Microsoft.AspNetCore.Server.Kestrel.Https를 참조하는 라이브러리는 ASP.NET Core 종속성을 2.1 이상으로 업데이트해야 합니다.

ASP.NET Core 2.1 이상을 대상으로 하는 앱 및 라이브러리는 Microsoft.AspNetCore.Server.Kestrel.Https 패키지에 대한 직접 참조를 모두 제거해야 합니다.

Newtonsoft.Json(Json.NET) 지원

ASP.NET Core 공유 프레임워크를 개선하기 위한 노력의 일환으로, ASP.NET Core 공유 프레임워크에서 Newtonsoft.Json(Json.NET)이 제거되었습니다.

이제 ASP.NET Core의 기본 JSON 직렬 변환기는 .NET Core 3.0에 새로 도입된 System.Text.Json입니다. 가능한 경우 System.Text.Json을 사용하세요. System.Text.Json은 고성능이며 추가 라이브러리 종속성이 필요하지 않습니다. 그러나 System.Text.Json은 새로 도입되었기 때문에 현재 앱에 필요한 기능이 누락되어 있을 수 있습니다. 자세한 내용은 Newtonsoft.Json에서 System.Text.Json로 마이그레이션하는 방법을 참조하세요.

ASP.NET Core 3.0 SignalR 프로젝트에서 Newtonsoft.Json 사용

  • Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson NuGet 패키지를 설치합니다.

  • 클라이언트에서 AddNewtonsoftJsonProtocol 메서드 호출을 HubConnectionBuilder 인스턴스에 연결합니다.

    new HubConnectionBuilder()
        .WithUrl("/chathub")
        .AddNewtonsoftJsonProtocol(...)
        .Build();
    
  • 서버에서 AddNewtonsoftJsonProtocol 메서드 호출을 Startup.ConfigureServicesAddSignalR 메서드 호출에 연결합니다.

    services.AddSignalR()
        .AddNewtonsoftJsonProtocol(...);
    

ASP.NET Core 3.0 MVC 프로젝트에서 Newtonsoft.Json 사용

  • Microsoft.AspNetCore.Mvc.NewtonsoftJson 패키지를 설치합니다.

  • Startup.ConfigureServicesAddNewtonsoftJson을 호출하도록 업데이트합니다.

    services.AddMvc()
        .AddNewtonsoftJson();
    

    AddNewtonsoftJson은 다음과 같은 새 MVC 서비스 등록 메서드와 호환됩니다.

    • AddRazorPages
    • AddControllersWithViews
    • AddControllers
    services.AddControllers()
        .AddNewtonsoftJson();
    

    Newtonsoft.Json 설정은 AddNewtonsoftJson에 대한 호출에서 설정할 수 있습니다.

    services.AddMvc()
        .AddNewtonsoftJson(options =>
               options.SerializerSettings.ContractResolver =
                  new CamelCasePropertyNamesContractResolver());
    

    참고:AddNewtonsoftJson 메서드를 사용할 수 없는 경우, Microsoft.AspNetCore.Mvc.NewtonsoftJson 패키지를 설치했는지 확인하세요. 종종 실수로 Microsoft.AspNetCore.Mvc.NewtonsoftJson 패키지 대신 Newtonsoft.Json 패키지를 설치하는 경우가 있습니다.

자세한 내용은 Newtonsoft.Json 기반 JSON 형식 지원 추가를 참조하세요.

MVC 서비스 등록

ASP.NET Core 3.0에 Startup.ConfigureServices에서 MVC 시나리오를 등록하기 위한 새로운 옵션이 추가되었습니다.

IServiceCollection에서 MVC 시나리오와 관련된 세 개의 최상위 수준 확장 메서드를 사용할 수 있습니다. 템플릿은 AddMvc 대신 이러한 새 메서드를 사용합니다. 그러나 AddMvc는 계속해서 이전 릴리스와 동일하게 동작합니다.

다음 예제에서는 컨트롤러와 API 관련 기능에 대한 지원을 추가합니다(보기 및 페이지에 대한 지원은 추가하지 않음). API 템플릿은 다음 코드를 사용합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}

다음 예제에서는 컨트롤러, API 관련 기능 및 보기에 대한 지원을 추가합니다(페이지에 대한 지원은 추가하지 않음). 웹 애플리케이션(MVC) 템플릿은 다음 코드를 사용합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
}

다음 예제에서는 Razor Pages에 대한 지원과 최소한의 컨트롤러 지원을 추가합니다. 웹 애플리케이션 템플릿은 다음 코드를 사용합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
}

새 메서드를 결합하는 것도 가능합니다. 다음 예제는 ASP.NET Core 2.2에서 AddMvc를 호출하는 것과 동일합니다.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();
}

라우팅 시작 코드

앱이 UseMvc 또는 UseSignalR을 호출한다면 가능한 경우 앱을 엔드포인트 라우팅으로 마이그레이션하세요. 이전 버전의 MVC와의 엔드포인트 라우팅 호환성을 개선하기 위해, ASP.NET Core 2.2에 도입되었던 URL 생성 변경 사항의 일부가 복원되었습니다. 2.2에서 엔드포인트 라우팅을 사용하는 데 문제가 있었다면 ASP.NET Core 3.0에서는 이러한 문제가 개선되었을 것입니다. 단, 다음과 같은 예외가 있습니다.

  • 앱이 IRouter를 구현하거나 Route에서 상속받는 경우 DynamicRouteValuesTransformer를 대체로 사용하세요.
  • 앱이 MVC 안에서 RouteData.Routers에 직접 액세스하여 URL을 구문 분석하는 경우 LinkParser.ParsePathByEndpointName을 사용하여 대체할 수 있습니다.
    • 경로 이름을 사용하여 경로를 정의합니다.
    • LinkParser.ParsePathByEndpointName을 사용하여 원하는 경로 이름을 전달합니다.

엔드포인트 라우팅은 IRouter와 동일한 경로 패턴 구문과 경로 패턴 작성 기능을 지원합니다. 엔드포인트 라우팅은 IRouteConstraint를 지원합니다. 엔드포인트 라우팅은 [Route], [HttpGet] 및 기타 MVC 라우팅 특성을 지원합니다.

대부분의 애플리케이션에서는 Startup만 변경하면 됩니다.

Startup.Configure 마이그레이션

일반적인 조언:

  • UseRouting를 추가합니다.

  • 앱이 UseStaticFiles를 호출하는 경우, UseRouting앞에UseStaticFiles를 배치합니다.

  • 앱이 AuthorizePage[Authorize]와 같은 인증/권한 부여 기능을 사용하는 경우 호출을 UseAuthenticationUseAuthorization에서 UseRoutingUseCors뒤에UseEndpoints 앞에 배치합니다.

    public void Configure(IApplicationBuilder app)
    {
      ...
    
      app.UseStaticFiles();
    
      app.UseRouting();
      app.UseCors();
    
      app.UseAuthentication();
      app.UseAuthorization();
    
      app.UseEndpoints(endpoints => {
         endpoints.MapControllers();
      });
    
  • UseMvc 또는 UseSignalRUseEndpoints로 대체합니다.

  • 앱이 [EnableCors]와 같은 CORS 시나리오를 사용하는 경우 CORS를 사용하는 다른 모든 미들웨어 앞에 UseCors에 대한 호출을 배치합니다(예: UseCorsUseAuthentication, UseAuthorization, UseEndpoints 앞에 배치).

  • IHostingEnvironmentIWebHostEnvironment로 대체하고 Microsoft.AspNetCore.Hosting 네임스페이스에 대한 using 문을 추가합니다.

  • IApplicationLifetimeIHostApplicationLifetime으로 대체합니다(Microsoft.Extensions.Hosting 네임스페이스).

  • EnvironmentNameEnvironments으로 대체합니다(Microsoft.Extensions.Hosting 네임스페이스).

다음 코드는 일반적인 ASP.NET Core 2.2 앱의 Startup.Configure의 예시입니다.

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseStaticFiles();

    app.UseAuthentication();

    app.UseSignalR(hubs =>
    {
        hubs.MapHub<ChatHub>("/chat");
    });

    app.UseMvc(routes =>
    {
        routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });
}

이전 Startup.Configure 코드를 업데이트한 후에:

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseStaticFiles();

    app.UseRouting();

    app.UseCors();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<ChatHub>("/chat");
        endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
    });
}

Warning

대부분의 앱에서 UseAuthentication, UseAuthorization, UseCors에 대한 호출이 효력을 가지려면 UseRouting에 대한 호출과 UseEndpoints에 대한 호출 사이에 와야 합니다.

상태 검사

상태 검사는 제네릭 호스트와의 엔드포인트 라우팅을 사용합니다. Startup.Configure에서 엔드포인트 URL 또는 상대 경로를 사용하여 엔드포인트 작성기에 MapHealthChecks를 호출합니다.

app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health");
});

상태 검사 엔드포인트는 다음을 수행할 수 있습니다.

  • 허용되는 호스트/포트를 하나 이상 지정합니다.
  • 권한 부여가 필요합니다.
  • CORS가 필요합니다.

자세한 내용은 ASP.NET Core의 상태 검사을 참조하세요.

보안 미들웨어 지침

권한 부여 및 CORS에 대한 지원이 미들웨어 접근 방식을 중심으로 통합되었습니다. 이에 따라 이러한 시나리오에서 동일한 미들웨어와 기능을 사용할 수 있게 되었습니다. 이번 릴리스에서는 업데이트된 권한 부여 미들웨어가 제공되었으며, CORS 미들웨어는 MVC 컨트롤러가 사용하는 특성을 이해할 수 있도록 개선되었습니다.

CORS

이전에는 CORS를 구성하는 작업이 쉽지 않았습니다. 일부 사용 사례에서 사용할 수 있는 미들웨어가 제공되긴 했지만, 그 밖의 사용 사례에서는 미들웨어 없이 MVC 필터를 사용해야 했습니다. ASP.NET Core 3.0에서는 CORS가 필요한 모든 앱이 CORS 미들웨어를 엔드포인트 라우팅과 함께 사용해야 합니다. UseCors는 기본 정책을 사용하여 제공할 수 있으며, 필요한 경우 [EnableCors][DisableCors] 특성을 사용하여 기본 정책을 재정의할 수 있습니다.

다음 예제에서

  • CORS는 default 명명된 정책을 갖는 모든 엔드포인트에서 사용하도록 설정됩니다.
  • MyController 클래스는 [DisableCors] 특성을 사용하여 CORS를 사용하지 않도록 설정합니다.
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseCors("default");

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

[DisableCors]
public class MyController : ControllerBase
{
    ...
}

Authorization

이전 버전의 ASP.NET Core에서는 권한 부여 지원이 [Authorize] 특성을 통해 제공되었습니다. 권한 부여 미들웨어는 없었습니다. ASP.NET Core 3.0에서는 권한 부여 미들웨어가 요구됩니다. ASP.NET Core 권한 부여 미들웨어(UseAuthorization)를 UseAuthentication 직후에 배치하는 것을 권장합니다. 권한 부여 미들웨어는 기본 정책을 사용하여 구성할 수도 있으며, 기본 정책은 재정의할 수 있습니다.

ASP.NET Core 3.0 이상에서는 UseAuthorizationStartup.Configure에서 호출됩니다. 아래의 HomeController에서는 로그인한 사용자가 필요합니다.

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

public class HomeController : Controller
{
    [Authorize]
    public IActionResult BuyWidgets()
    {
        ...
    }
}

엔드포인트 라우팅을 사용할 때는 AuthorizeFilter를 사용하지 말고 권한 부여 미들웨어를 사용하시기 바랍니다. 앱이 AuthorizeFilter를 MVC의 전역 필터로 사용하는 경우, 코드가 AddAuthorization에 대한 호출에서 정책을 제공하도록 리팩터링하는 것을 권장합니다.

DefaultPolicy는 인증을 요구하도록 초기 구성되므로 추가 구성이 필요하지 않습니다. 다음 예제에서는 MVC 엔드포인트가 RequireAuthorization으로 표시되어 있으므로 모든 요청이 DefaultPolicy에 따라 권한 부여되어야 합니다. 그러나 HomeController에는 [AllowAnonymous]가 있기 때문에 사용자가 앱에 로그인하지 않아도 액세스를 허용합니다.

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute().RequireAuthorization();
    });
}

[AllowAnonymous]
public class HomeController : Controller
{
    ...
}

특정 엔드포인트의 권한 부여

특정 엔드포인트 클래스에 대해서도 권한 부여를 구성할 수 있습니다. 다음 코드는 전역 AuthorizeFilter를 구성한 MVC 앱을 권한 부여가 필요한 특정 정책을 갖는 앱으로 변환하는 예입니다.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    static readonly string _RequireAuthenticatedUserPolicy = 
                            "RequireAuthenticatedUserPolicy";
    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(
                 options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        // Pre 3.0:
        // services.AddMvc(options => options.Filters.Add(new AuthorizeFilter(...));

        services.AddControllersWithViews();
        services.AddRazorPages();
        services.AddAuthorization(o => o.AddPolicy(_RequireAuthenticatedUserPolicy,
                        builder => builder.RequireAuthenticatedUser()));

    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute()
                .RequireAuthorization(_RequireAuthenticatedUserPolicy);
            endpoints.MapRazorPages();
        });
    }
}

정책을 사용자 지정하는 것도 가능합니다. DefaultPolicy는 인증을 요구하도록 구성되었습니다.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(
                 options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddControllersWithViews();
        services.AddRazorPages();
        services.AddAuthorization(options =>
        {
            options.DefaultPolicy = new AuthorizationPolicyBuilder()
              .RequireAuthenticatedUser()
              .Build();
        });

    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute().RequireAuthorization();
            endpoints.MapRazorPages();
        });
    }
}
[AllowAnonymous]
public class HomeController : Controller
{

또는 FallbackPolicy를 구성하여 [Authorize] 또는 RequireAuthorization 없이도 권한 부여를 요구하도록 모든 엔드포인트를 구성할 수도 있습니다. FallbackPolicyDefaultPolicy와 다릅니다. DefaultPolicy[Authorize] 또는 RequireAuthorization에 의해 트리거되는 반면 FallbackPolicy는 설정된 다른 정책이 없는 경우에 트리거됩니다. FallbackPolicy는 권한 부여 없이 요청을 허용하도록 초기 구성됩니다.

다음 예제는 위의 DefaultPolicy 예제와 동일하나, [AllowAnonymous]가 지정된 경우를 제외하고 항상 모든 엔드포인트에서 인증을 요구하도록 FallbackPolicy를 사용합니다.

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddAuthorization(options =>
    {
        options.FallbackPolicy = new AuthorizationPolicyBuilder()
          .RequireAuthenticatedUser()
          .Build();
    });
}

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

[AllowAnonymous]
public class HomeController : Controller
{
    ...
}

미들웨어에 의한 권한 부여는 프레임워크에 권한 부여에 대한 구체적인 지식이 없는 상태로 작동합니다. 예를 들어, 상태 검사는 권한 부여에 대한 구체적인 지식이 없지만 미들웨어에 의해 적용된 구성 가능한 권한 부여 정책을 가질 수 있습니다.

이에 더해, 각 엔드포인트는 자체 권한 부여 요구 사항을 사용자 지정할 수 있습니다. 다음 예제에서 UseAuthorizationDefaultPolicy를 사용하여 권한 부여를 처리하는 반면 /healthz 상태 검사 엔드포인트에는 admin 사용자가 필요합니다.

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints
            .MapHealthChecks("/healthz")
            .RequireAuthorization(new AuthorizeAttribute(){ Roles = "admin", });
    });
}

일부 시나리오에서는 보호가 구현됩니다. 엔드포인트 미들웨어는 미들웨어가 누락되어 권한 부여 또는 CORS 정책을 건너뛴 경우 예외를 throw합니다. 잘못된 구성에 대한 추가 피드백을 제공하기 위한 분석기 지원은 현재 구현 중입니다.

사용자 지정 권한 부여 처리기

앱이 사용자 지정 권한 부여 처리기를 사용하는 경우, 엔드포인트 라우팅은 처리기에 MVC와 다른 리소스 유형을 전달합니다. 권한 부여 처리기 컨텍스트 리소스의 형식이 AuthorizationFilterContext(MVC 필터가 제공하는 리소스 형식)여야 하는 처리기는 RouteEndpoint 리소스 형식(엔드포인트 라우팅이 권한 부여 처리기에 제공하는 리소스 형식)을 처리하도록 업데이트해야 합니다.

MVC는 여전히 AuthorizationFilterContext 리소스를 사용하므로, 앱이 엔드포인트 라우팅 권한 부여와 함께 MVC 권한 부여 필터를 사용하는 경우 두 가지 리소스 형식을 처리해야 할 수 있습니다.

SignalR

SignalR 허브의 매핑은 이제 UseEndpoints에서 이루어집니다.

각 허브를 MapHub를 사용하여 매핑하세요. 이전 버전에서와 마찬가지로, 각 허브는 명시적으로 나열됩니다.

다음 예제에서는 ChatHubSignalR 허브에 대한 지원이 추가됩니다.

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<ChatHub>();
    });
}

클라이언트에서 메시지 크기 제한을 제어하기 위한 새로운 옵션이 있습니다. 예를 들어 Startup.ConfigureServices에 만듭니다.

services.AddSignalR(hubOptions =>
{
    hubOptions.MaximumReceiveMessageSize = 32768;
});

ASP.NET Core 2.2에서는 TransportMaxBufferSize를 설정하여 최대 메시지 크기를 제어할 수 있었습니다. ASP.NET Core 3.0에서 이 옵션은 역 압력이 관찰되기 전에만 최대 크기를 제어합니다.

SignalR 공유 프레임워크의 어셈블리

ASP.NET Core SignalR 서버 쪽 어셈블리는 이제 .NET Core SDK와 함께 설치됩니다. 자세한 내용은 이 문서에서 사용되지 않는 패키지 참조 제거를 참조하세요.

MVC 컨트롤러

컨트롤러의 매핑은 이제 UseEndpoints에서 이루어집니다.

앱이 특성 라우팅을 사용하는 경우 MapControllers를 추가하세요. 라우팅은 ASP.NET Core 3.0 이상의 여러 프레임워크에 대한 지원을 포함하므로, 특성으로 라우팅되는 컨트롤러를 추가하는 것은 선택 사항입니다.

다음 내용을

  • MapRoute(MapControllerRoute 사용)
  • MapAreaRoute(MapAreaControllerRoute 사용)

이제 라우팅은 MVC 외의 여러 프레임워크에 대한 지원을 포함하므로, 이러한 메서드가 하는 일을 명확히 알 수 있도록 용어가 변경되었습니다. MapControllerRoute/MapAreaControllerRoute/MapDefaultControllerRoute와 같은 규칙 기반 경로는 추가된 순서대로 적용됩니다. 보다 구체적인 경로(예: 영역에 대한 경로)를 먼저 배치하세요.

다음 예제에서

  • MapControllers는 특성으로 라우팅되는 컨트롤러에 대한 지원을 추가합니다.
  • MapAreaControllerRoute는 한 영역에 있는 컨트롤러에 대한 규칙 기반 경로를 추가합니다.
  • MapControllerRoute는 컨트롤러에 대한 규칙 기반 경로를 추가합니다.
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapAreaControllerRoute(
            "admin",
            "admin",
            "Admin/{controller=Home}/{action=Index}/{id?}");
        endpoints.MapControllerRoute(
            "default", "{controller=Home}/{action=Index}/{id?}");
    });
}

컨트롤러 작업 이름에서 비동기 접미사 제거

ASP.NET Core 3.0에서, ASP.NET Core MVC의 컨트롤러 작업 이름에서 Async 접미사가 제거되었습니다. 이 새로운 기본값은 라우팅 및 링크 생성에 영향을 줍니다. 예시:

public class ProductsController : Controller
{
    public async Task<IActionResult> ListAsync()
    {
        var model = await _dbContext.Products.ToListAsync();
        return View(model);
    }
}

ASP.NET Core 3.0 이전:

  • 위 작업은 Products/ListAsync 경로에서 액세스할 수 있었습니다.

  • 링크를 생성하려면 Async 접미사를 지정해야 했습니다. 예시:

    <a asp-controller="Products" asp-action="ListAsync">List</a>
    

ASP.NET Core 3.0:

  • 위 작업은 Products/List 경로에서 액세스할 수 있습니다.

  • 링크 생성을 위해 Async 접미사를 지정할 필요가 없습니다. 예시:

    <a asp-controller="Products" asp-action="List">List</a>
    

이 변경은 [ActionName] 특성을 사용하여 지정된 이름에는 영향을 주지 않습니다. 기본 동작은 Startup.ConfigureServices에서 다음 코드를 사용하여 사용하지 않도록 설정할 수 있습니다.

services.AddMvc(options =>
    options.SuppressAsyncSuffixInActionNames = false);

링크 생성에는 몇 가지 차이점이 있습니다(예: Url.Link 및 유사한 API 사용). 여기에는 다음이 포함됩니다.

  • 기본적으로, 엔드포인트 라우팅을 사용할 때는 생성된 URI의 경로 매개 변수의 대소문자 구분이 보존되지 않을 수 있습니다. 이 동작은 IOutboundParameterTransformer 인터페이스를 통해 제어할 수 있습니다.
  • 유효하지 않은 경로(존재하지 않는 컨트롤러/작업 또는 페이지)에 대해 URI를 생성하면 유효하지 않은 URI가 생성되는 대신 엔드포인트 라우팅 아래에 빈 문자열이 생성됩니다.
  • 앰비언트 값(현재 컨텍스트의 경로 매개 변수)는 엔드포인트 라우팅을 사용하는 링크 생성에서 자동으로 사용되지 않습니다. 기존에는 다른 작업(또는 페이지)로의 링크를 생성할 때 ‘현재’ 경로 앰비언트 값으로부터 지정되지 않은 경로 값이 유추되었습니다. 엔드포인트 라우팅을 사용할 때는 링크 생성 중에 모든 경로 매개 변수를 명시적으로 지정해야 합니다.

Razor Pages

Razor Pages의 매핑은 이제 UseEndpoints에서 이루어집니다.

앱이 Razor Pages를 사용하는 경우 MapRazorPages를 추가하세요. 엔드포인트 라우팅은 여러 프레임워크에 대한 지원을 포함하므로 이제 Razor Pages를 추가하는 것은 선택 사항입니다.

다음 Startup.Configure 메서드에서 MapRazorPages는 Razor Pages에 대한 지원을 추가합니다.

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

엔드포인트 라우팅 없이 MVC 사용

ASP.NET Core 3.0에서 UseMvc 또는 UseMvcWithDefaultRoute를 통해 MVC를 사용하려면 Startup.ConfigureServices 내에서 명시적으로 옵트인해야 합니다. 이는 MVC가 초기화 중에 권한 부여 및 CORS 미들웨어를 사용할 수 있는지 여부를 알아야 하기 때문에 요구됩니다. 앱이 지원되지 않는 구성을 사용하려고 시도하는 경우 경고를 발생시키는 분석기가 제공됩니다.

앱에 레거시 IRouter 지원이 필요한 경우, Startup.ConfigureServices에서 다음 방법 중 하나를 사용하여 EnableEndpointRouting을 사용하지 않도록 설정하세요.

services.AddMvc(options => options.EnableEndpointRouting = false);
services.AddControllers(options => options.EnableEndpointRouting = false);
services.AddControllersWithViews(options => options.EnableEndpointRouting = false);
services.AddRazorPages().AddMvcOptions(options => options.EnableEndpointRouting = false);

상태 검사

상태 검사는 엔드포인트 라우팅과 함께 ‘라우터웨어’로 사용할 수 있습니다.

엔드포인트 라우팅과 함께 상태 검사를 사용하려면 MapHealthChecks를 추가하세요. MapHealthChecks 메서드는 UseHealthChecks와 비슷한 인수를 받습니다. UseHealthChecks 대신 MapHealthChecks를 사용하면 권한 부여를 적용할 수 있고 매칭 정책을 보다 세밀하게 제어할 수 있다는 이점이 있습니다.

다음 예제에서, /healthz에서의 상태 검사 엔드포인트에 MapHealthChecks가 호출됩니다.

public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHealthChecks("/healthz", new HealthCheckOptions() { });
    });
}

HostBuilder가 WebHostBuilder를 대체함

ASP.NET Core 3.0 템플릿은 제네릭 호스트를 사용합니다. 이전 버전에서는 웹 호스트를 사용했습니다. 다음 코드는 ASP.NET Core 3.0 템플릿에서 생성된 Program 클래스를 보여 줍니다.

// requires using Microsoft.AspNetCore.Hosting;
// requires using Microsoft.Extensions.Hosting;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

다음 코드는 ASP.NET Core 2.2 템플릿에서 생성된 Program 클래스를 보여 줍니다.

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

IWebHostBuilder는 3.0에도 남아 있으며, 위의 코드 샘플에서 볼 수 있는 webBuilder의 형식입니다. WebHostBuilder는 이후 릴리스에서 더 이상 사용되지 않고 HostBuilder로 대체됩니다.

WebHostBuilder에서 HostBuilder로 변경됨에 따라 주목해야 할 가장 큰 차이는 DI(종속성 삽입)입니다. HostBuilder를 사용할 때는 Startup의 생성자에 다음 항목만 삽입할 수 있습니다.

HostBuilder DI는 제한 사항은:

  • DI 컨테이너가 한 번만 빌드되도록 합니다.
  • 여러 인스턴스의 싱글톤 확인과 같은 결과 개체 수명 문제를 방지합니다.

자세한 내용은 Avoiding Startup service injection in ASP.NET Core 3(ASP.NET Core 3에서 시작 서비스 삽입 방지)을 참조하세요.

AddAuthorization이 다른 어셈블리로 이동됨

Microsoft.AspNetCore.Authorization.dll의 ASP.NET Core 2.2 이하 AddAuthorization 메서드는:

  • AddAuthorizationCore로 이름이 변경되었습니다.
  • Microsoft.AspNetCore.Authorization.Policy.dll로 이동되었습니다.

Microsoft.AspNetCore.Authorization.dllMicrosoft.AspNetCore.Authorization.Policy.dll을 모두 사용하는 앱은 영향을 받지 않습니다.

Microsoft.AspNetCore.Authorization.Policy.dll을 사용하지 않는 앱은 다음 중 하나를 수행해야 합니다.

  • Microsoft.AspNetCore.Authorization.Policy.dll에 대한 참조를 추가합니다. 이 방법은 대부분의 앱에서 작동하며, 요구되는 유일한 작업입니다.
  • AddAuthorizationCore 사용으로 전환합니다.

자세한 내용은 Breaking change in AddAuthorization(o =>) overload lives in a different assembly #386(AddAuthorization(o =>) 오버로드의 호환성이 손상되는 변경이 다른 어셈블리에 있음 #386)을 참조하세요.

Identity Ui

ASP.NET Core 3.0의 Identity UI 업데이트:

  • Microsoft.AspNetCore.Identity.UI에 대한 패키지 참조를 추가합니다.
  • Razor Pages를 사용하지 않는 앱은 MapRazorPages를 호출해야 합니다. 본 문서의 Razor Pages를 참조하세요.
  • 부트스트랩 4가 기본 UI 프레임워크입니다. 기본값을 변경하려면 IdentityUIFrameworkVersion 프로젝트 속성을 설정하세요. 자세한 내용은 GitHub 공지를 참조하세요.

SignalR

SignalR JavaScript 클라이언트가 @aspnet/signalr에서 @microsoft/signalr로 변경되었습니다. 이 변경에 대응하려면 파일, require 문 및 ECMAScript import 문의 참조 package.json 를 변경합니다.

System.Text.Json이 기본 프로토콜임

이제 System.Text.Json이 클라이언트와 서버가 사용하는 기본 허브 프로토콜입니다.

Startup.ConfigureServices에서 AddJsonProtocol을 호출하여 직렬 변환기 옵션을 설정합니다.

서버:

services.AddSignalR(...)
        .AddJsonProtocol(options =>
        {
            options.PayloadSerializerOptions.WriteIndented = false;
        })

클라이언트:

new HubConnectionBuilder()
    .WithUrl("/chathub")
    .AddJsonProtocol(options =>
    {
        options.PayloadSerializerOptions.WriteIndented = false;
    })
    .Build();

Newtonsoft.Json으로 전환

System.Text.Json에서 지원되지 않는 Newtonsoft.Json의 기능을 사용하는 경우, Newtonsoft.Json으로 다시 전환할 수 있습니다. 본 문서의 ASP.NET Core 3.0 SignalR 프로젝트에서 Newtonsoft.Json 사용을 참조하세요.

Redis 분산 캐시

ASP.NET Core 3.0 이상 앱에서는 Microsoft.Extensions.Caching.Redis 패키지를 사용할 수 없습니다. 패키지 참조를 Microsoft.Extensions.Caching.StackExchangeRedis로 대체하세요. 자세한 내용은 ASP.NET Core의 분산 캐싱을 참조하세요.

런타임 컴파일에 옵트인

ASP.NET Core 3.0 이전에는 보기의 런타임 컴파일이 프레임워크의 암시적 기능이었습니다. 런타임 컴파일은 보기의 빌드 시간 컴파일을 보완합니다. 전체 앱을 다시 빌드 Razor 하지 않고도 파일이 수정될 때 프레임워크에서 보기 및 페이지(.cshtml 파일)를 컴파일할 수 있습니다. 이 기능은 IDE에서 빠른 편집을 적용하고 브라우저를 새로 고침하여 변경 내용을 확인하는 시나리오를 지원합니다.

ASP.NET Core 3.0에서는 런타임 컴파일이 옵트인 시나리오가 되었습니다. 빌드 시간 컴파일은 보기 컴파일에 대해 기본적으로 설정되는 유일한 메커니즘입니다. 런타임은 Visual Studio Code의 Visual Studio 또는 dotnet-watch 를 사용하여 파일의 변경 내용을 .cshtml 감지할 때 프로젝트를 다시 빌드합니다. Visual Studio에서 실행 중인 프로젝트의 파일(Ctrl+F5)을 변경 .cshtml.razor.cs하지만 디버그되지 않음(F5)은 프로젝트의 다시 컴파일을 트리거합니다.

ASP.NET Core 3.0 프로젝트에서 런타임 컴파일을 사용하도록 설정하려면:

  1. Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation NuGet 패키지를 설치합니다.

  2. Startup.ConfigureServicesAddRazorRuntimeCompilation을 호출하도록 업데이트합니다.

    ASP.NET Core MVC에서는 다음 코드를 사용합니다.

    services.AddControllersWithViews()
        .AddRazorRuntimeCompilation(...);
    

    ASP.NET Core Razor Pages에서는 다음 코드를 사용합니다.

    services.AddRazorPages()
        .AddRazorRuntimeCompilation(...);
    

https://github.com/aspnet/samples/tree/main/samples/aspnetcore/mvc/runtimecompilation의 샘플은 개발 환경에서 조건부로 런타임 컴파일을 사용하도록 설정하는 예제를 보여 줍니다.

Razor 파일 컴파일에 대한 자세한 내용은 ASP.NET Core Razor에서 파일 컴파일을 참조하세요.

다중 대상 지정을 통해 라이브러리 마이그레이션

라이브러리가 ASP.NET Core의 여러 버전을 지원해야 하는 경우가 있습니다. 이전 버전의 ASP.NET Core에 대해 컴파일된 대부분의 라이브러리는 계속해서 문제없이 작동할 것입니다. 아래와 같은 조건에서는 앱을 교차 컴파일해야 합니다.

  • 라이브러리가 이진 호환성을 손상하는 변경이 있는 기능을 사용합니다.
  • 라이브러리가 ASP.NET Core 3.0의 새로운 기능을 사용해야 합니다.

예시:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netcoreapp3.0;netstandard2.0</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
    <PackageReference Include="Microsoft.AspNetCore" Version="2.1.0" />
  </ItemGroup>
</Project>

#ifdefs를 사용하여 ASP.NET Core 3.0 API를 사용하도록 설정합니다.

var webRootFileProvider =
#if NETCOREAPP3_0
    GetRequiredService<IWebHostEnvironment>().WebRootFileProvider;
#elif NETSTANDARD2_0
    GetRequiredService<IHostingEnvironment>().WebRootFileProvider;
#else
#error unknown target framework
#endif

클래스 라이브러리에서 ASP.NET Core API를 사용하는 방법에 대한 자세한 내용은 클래스 라이브러리에서 ASP.NET Core API 사용을 참조하세요.

기타 변경 내용

.NET Core 3.0 이상의 유효성 검사 시스템은 Null을 허용하지 않는 매개 변수 또는 바인딩된 속성을 [Required] 특성을 포함한 것처럼 처리합니다. 자세한 내용은 [Required] 특성을 참조하세요.

게시

프로젝트 디렉터리에서 bin 폴더와 obj 폴더를 삭제합니다.

TestServer

제네릭 호스트TestServer를 직접 사용하는 앱의 경우 ConfigureWebHost에서 IWebHostBuilderTestServer를 만듭니다.

[Fact]
public async Task GenericCreateAndStartHost_GetTestServer()
{
    using var host = await new HostBuilder()
        .ConfigureWebHost(webBuilder =>
        {
            webBuilder
                .UseTestServer()
                .Configure(app => { });
        })
    .StartAsync();

    var response = await host.GetTestServer().CreateClient().GetAsync("/");

    Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}

호환성이 손상되는 API 변경

호환성이 손상되는 변경 검토:

catch-all 매개 변수를 사용한 엔드포인트 라우팅

Warning

catch-all 매개 변수는 라우팅의 버그로 인해 경로와 일치하지 않을 수 있습니다. 이 버그의 영향을 받는 앱은 다음과 같은 특징이 있습니다.

  • catch-all 경로(예: {**slug}")
  • catch-all 경로가 일치해야 하는 요청과 일치하지 않습니다.
  • 다른 경로를 제거하면 catch-all 경로 작동이 시작됩니다.

이 버그에 해당하는 사례는 GitHub 버그 1867716579를 참조하세요.

이 버그에 대한 옵트인 픽스가 .NET Core 3.1.301 SDK 이상에 포함되어 있습니다. 다음 코드는 이 버그를 수정하는 내부 스위치를 설정합니다.

public static void Main(string[] args)
{
   AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior", 
                         true);
   CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.

Azure App Service의 .NET Core 3.0

.NET Core의 Azure App Service로의 출시가 완료되었습니다. 이제 모든 Azure App Service 데이터 센터에서 .NET Core 3.0을 사용할 수 있습니다.

ASP.NET Core 모듈(ANCM)

Visual Studio를 설치할 때 ANCM(ASP.NET Core 모듈)이 선택된 구성 요소가 아니거나 이전 버전의 ANCM이 시스템에 설치된 경우, 최신 .NET Core 호스팅 번들 설치 관리자(직접 다운로드)를 다운로드하고 설치 관리자를 실행합니다. 자세한 내용은 호스팅 번들을 참조하세요.