다음을 통해 공유


ASP.NET Core 9.0의 새로운 기능

이 문서에서는 ASP.NET Core 9.0의 가장 중요한 변경 내용과 관련 설명서에 대한 링크를 강조 표시합니다.

이 문서는 .NET 9 미리 보기 4용으로 업데이트되었습니다.

Blazor

이 섹션에서는 .에 대한 새로운 기능에 대해 설명합니다 Blazor.

전역 대화형 Blazor 웹앱에 정적 SSR(서버 쪽 렌더링) 페이지 추가

.NET 9 릴리스에서는 이제 전역 대화형 작업을 채택하는 앱에 정적 SSR 페이지를 더 간단하게 추가할 수 있습니다.

이 방법은 앱에 대화형 서버 또는 WebAssembly 렌더링을 사용할 수 없는 특정 페이지가 있는 경우에만 유용합니다. 예를 들어 HTTP cookie읽기/쓰기에 의존하며 대화형 렌더링 대신 요청/응답 주기에서만 작동할 수 있는 페이지에 이 방법을 채택합니다. 대화형 렌더링을 사용하는 페이지의 경우 최종 사용자에게 덜 효율적이고 응답성이 떨어지기 때문에 정적 SSR 렌더링을 사용하도록 강요해서는 안 됩니다.

지시 Razor 문과 함께 할당된 새 [ExcludeFromInteractiveRouting] 특성으로 @attributeRazor 구성 요소 페이지를 표시합니다.

@attribute [ExcludeFromInteractiveRouting]

특성을 적용하면 페이지 탐색이 대화형 라우팅에서 종료됩니다. 인바운드 탐색은 대화형 라우팅을 통해 페이지를 확인하는 대신 전체 페이지 다시 로드를 수행해야 합니다. 전체 페이지 다시 로드는 최상위 루트 구성 요소(일반적으로 App 구성 요소)App.razor가 서버에서 다시 렌더링되도록 하여 앱이 다른 최상위 렌더링 모드로 전환되도록 합니다.

HttpContext.AcceptsInteractiveRouting 확장 메서드를 사용하면 구성 요소가 현재 페이지에 적용되는지 여부를 [ExcludeFromInteractiveRouting] 검색할 수 있습니다.

구성 요소에서 App 다음 예제의 패턴을 사용합니다.

  • 전역 대화형 작업으로 렌더링 모드에 [ExcludeFromInteractiveRouting] 기본적으로 주석이 InteractiveServer 추가되지 않은 페이지입니다. 다른 기본 전역 렌더링 모드로 InteractiveWebAssembly 바꾸 InteractiveServer 거나 InteractiveAuto 지정할 수 있습니다.
  • 정적 SSR 채택으로 [ExcludeFromInteractiveRouting] 주석이 추가된 페이지(PageRenderMode 할당됨 null).
<!DOCTYPE html>
<html>
<head>
    ...
    <HeadOutlet @rendermode="@PageRenderMode" />
</head>
<body>
    <Routes @rendermode="@PageRenderMode" />
    ...
</body>
</html>

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? PageRenderMode
        => HttpContext.AcceptsInteractiveRouting() ? InteractiveServer : null;
}

확장 메서드를 HttpContext.AcceptsInteractiveRouting 사용하는 대안은 .를 사용하여 HttpContext.GetEndpoint()?.Metadata수동으로 엔드포인트 메타데이터를 읽는 것입니다.

이 기능은 ASP.NET Core Blazor 렌더링 모드의 참조 설명서에서 다룹니다.

생성자 주입

Razor 구성 요소는 생성자 주입을 지원합니다.

다음 예제에서 부분(코드 숨김) 클래스는 기본 생성자를 사용하여 서비스를 삽입합니다NavigationManager.

public partial class ConstructorInjection(NavigationManager navigation)
{
    protected NavigationManager Navigation { get; } = navigation;
}

자세한 내용은 ASP.NET Core Blazor 종속성 주입을 참조하세요.

대화형 서버 구성 요소에 대한 Websocket 압축

기본적으로 대화형 서버 구성 요소는 WebSocket 연결에 대한 압축을 사용하도록 설정하고 CSP(콘텐츠 보안 정책) 지시문으로 설정합니다'self'frame-ancestors. 이 지시문은 압축을 사용하도록 설정하거나 WebSocket 컨텍스트에 대한 구성이 제공될 때 앱이 제공되는 원본에만 앱을 포함 <iframe> 할 수 있도록 허용합니다.

압축을 설정하여 사용하지 않도록 설정할 ConfigureWebSocketOptions 수 있습니다. 그러면 공격null앱의 취약성이 줄어들지만 성능이 저하될 수 있습니다.

.AddInteractiveServerRenderMode(o => o.ConfigureWebSocketOptions = null)

WebSocket 압축을 허용하지만 브라우저가 앱을 포함할 수 없도록 하는 값 'none' (작은따옴표 필요)으로 <iframe>frame-ancestors 엄격한 CSP를 구성합니다.

.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")

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

에서 키보드 컴퍼지션 이벤트 처리 Blazor

KeyboardEventArgs.IsComposing 속성은 키보드 이벤트가 컴퍼지션 세션의 일부인지를 나타냅니다. 키보드 이벤트의 컴퍼지션 상태를 추적하는 것은 국제 문자 입력 메서드를 처리하는 데 매우 중요합니다.

에 매개 변수가 추가됨 OverscanCountQuickGrid

QuickGrid 이제 구성 요소는 가상화를 사용할 때 표시되는 영역 전후에 렌더링되는 추가 행 수를 지정하는 속성을 노출 OverscanCount 합니다.

기본값 OverscanCount 은 3입니다. 다음 예제에서는 4로 늘입니다 OverscanCount .

<QuickGrid ItemsProvider="itemsProvider" Virtualize="true" OverscanCount="4">
    ...
</QuickGrid>

SignalR

이 섹션에서는 .에 대한 새로운 기능에 대해 설명합니다 SignalR.

허브의 SignalR 다형 형식 지원

이제 허브 메서드는 파생 클래스 대신 기본 클래스를 수락하여 다형 시나리오를 사용하도록 설정할 수 있습니다. 다형성을 허용하려면 기본 형식에 주석을 추가해야 합니다.

public class MyHub : Hub
{
    public void Method(JsonPerson person)
    {
        if (person is JsonPersonExtended)
        {
        }
        else if (person is JsonPersonExtended2)
        {
        }
        else
        {
        }
    }
}

[JsonPolymorphic]
[JsonDerivedType(typeof(JsonPersonExtended), nameof(JsonPersonExtended))]
[JsonDerivedType(typeof(JsonPersonExtended2), nameof(JsonPersonExtended2))]
private class JsonPerson
{
    public string Name { get; set; }
    public Person Child { get; set; }
    public Person Parent { get; set; }
}

private class JsonPersonExtended : JsonPerson
{
    public int Age { get; set; }
}

private class JsonPersonExtended2 : JsonPerson
{
    public string Location { get; set; }
}

최소 API

이 섹션에서는 최소 API에 대한 새로운 기능에 대해 설명합니다.

추가 InternalServerErrorInternalServerError<TValue>TypedResults

TypedResults 클래스는 최소 API에서 강력한 형식의 HTTP 상태 코드 기반 응답을 반환하는 데 유용한 수단입니다. TypedResults 이제 엔드포인트에서 "500 내부 서버 오류" 응답을 반환하기 위한 팩터리 메서드 및 형식이 포함됩니다. 다음은 500 응답을 반환하는 예제입니다.

var app = WebApplication.Create();

app.MapGet("/", () => TypedResults.InternalServerError("Something went wrong!"));

app.Run();

OpenAPI

OpenAPI 문서 생성에 대한 기본 제공 지원

OpenAPI 사양은 HTTP API를 설명하는 표준입니다. 이 표준을 통해 개발자는 클라이언트 생성기, 서버 생성기, 테스트 도구, 설명서 등에 연결할 수 있는 API의 모양을 정의할 수 있습니다. .NET 9 Preview에서 ASP.NET Core는 Microsoft.AspNetCore.OpenApi 패키지를 통해 컨트롤러 기반 또는 최소 API를 나타내는 OpenAPI 문서 생성을 기본적으로 지원합니다.

다음 강조 표시된 코드 호출은 다음과 같습니다.

  • AddOpenApi 필요한 종속성을 앱의 DI 컨테이너에 등록합니다.
  • MapOpenApi 앱의 경로에 필요한 OpenAPI 엔드포인트를 등록하려면 입니다.
var builder = WebApplication.CreateBuilder();

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapOpenApi();

app.MapGet("/hello/{name}", (string name) => $"Hello {name}"!);

app.Run();

Microsoft.AspNetCore.OpenApi 다음 명령을 사용하여 프로젝트에 패키지를 설치합니다.

dotnet add package Microsoft.AspNetCore.OpenApi --prerelease

앱을 실행하고 생성된 OpenAPI 문서를 보려면 다음 openapi/v1.json 을 수행합니다.

OpenAPI 문서

패키지를 추가하여 Microsoft.Extensions.ApiDescription.Server 빌드 시 OpenAPI 문서를 생성할 수도 있습니다.

dotnet add package Microsoft.Extensions.ApiDescription.Server --prerelease

앱의 프로젝트 파일에 다음을 추가합니다.

<PropertyGroup>
  <OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
  <OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
</PropertyGroup>

프로젝트 디렉터리에서 생성된 JSON 파일을 실행하고 dotnet build 검사합니다.

빌드 시 OpenAPI 문서 생성

ASP.NET Core의 기본 제공 OpenAPI 문서 생성은 다양한 사용자 지정 및 옵션을 지원합니다. 문서 및 작업 변환기를 제공하며 동일한 애플리케이션에 대해 여러 OpenAPI 문서를 관리할 수 있습니다.

ASP.NET Core의 새로운 OpenAPI 문서 기능에 대한 자세한 내용은 새 Microsoft.AspNetCore.OpenApi 문서를 참조 하세요.

인증 및 권한 부여

이 섹션에서는 인증 및 권한 부여를 위한 새로운 기능에 대해 설명합니다.

OIDC 및 OAuth 매개 변수 사용자 지정

이제 OAuth 및 OIDC 인증 처리기에는 AdditionalAuthorizationParameters 일반적으로 리디렉션 쿼리 문자열의 일부로 포함된 권한 부여 메시지 매개 변수를 보다 쉽게 사용자 지정할 수 있는 옵션이 제공됩니다. .NET 8 이전 버전에서는 사용자 지정 처리기에서 사용자 지정 OnRedirectToIdentityProvider 콜백 또는 재정의된 BuildChallengeUrl 메서드가 필요합니다. 다음은 .NET 8 코드의 예입니다.

builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
    options.Events.OnRedirectToIdentityProvider = context =>
    {
        context.ProtocolMessage.SetParameter("prompt", "login");
        context.ProtocolMessage.SetParameter("audience", "https://api.example.com");
        return Task.CompletedTask;
    };
});

이제 앞의 예제를 다음 코드로 간소화할 수 있습니다.

builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
    options.AdditionalAuthorizationParameters.Add("prompt", "login");
    options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});

HTTP.sys 확장 인증 플래그 구성

이제 HTTP.sys 새 EnableKerberosCredentialCaching 속성과 속성을 사용하여 플래그를 구성 HTTP_AUTH_EX_FLAG_ENABLE_KERBEROS_CREDENTIAL_CACHING 하고 HTTP_AUTH_EX_FLAG_CAPTURE_CREDENTIALCaptureCredentials HTTP.sys AuthenticationManager Windows 인증 처리 방법을 최적화할 수 있습니다. 예시:

webBuilder.UseHttpSys(options =>
{
    options.Authentication.Schemes = AuthenticationSchemes.Negotiate;
    options.Authentication.EnableKerberosCredentialCaching = true;
    options.Authentication.CaptureCredentials = true;
});

기타

다음 섹션에서는 기타 새로운 기능에 대해 설명합니다.

HybridCache 라이브러리

API는 HybridCache 기존 IDistributedCache API와 IMemoryCache API의 일부 격차를 해소합니다. 또한 다음과 같은 새로운 기능도 추가합니다.

  • 동일한 작업의 병렬 인출을 방지하기 위한 "Stampede" 보호 입니다.
  • 구성 가능한 serialization입니다.

HybridCache 는 기존 IDistributedCacheIMemoryCache 사용을 위한 드롭인 대체 기능으로 설계되었으며 새 캐싱 코드를 추가하기 위한 간단한 API를 제공합니다. In-Process 및 Out-of-process 캐싱 모두에 대한 통합 API를 제공합니다.

API가 HybridCache 간소화되는 방식을 확인하려면 API를 사용하는 IDistributedCache코드와 비교합니다. 다음은 사용 IDistributedCache 이 어떻게 표시되는지에 대한 예입니다.

public class SomeService(IDistributedCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        var key = $"someinfo:{name}:{id}"; // Unique key for this combination.
        var bytes = await cache.GetAsync(key, token); // Try to get from cache.
        SomeInformation info;
        if (bytes is null)
        {
            // Cache miss; get the data from the real source.
            info = await SomeExpensiveOperationAsync(name, id, token);

            // Serialize and cache it.
            bytes = SomeSerializer.Serialize(info);
            await cache.SetAsync(key, bytes, token);
        }
        else
        {
            // Cache hit; deserialize it.
            info = SomeSerializer.Deserialize<SomeInformation>(bytes);
        }
        return info;
    }

    // This is the work we're trying to cache.
    private async Task<SomeInformation> SomeExpensiveOperationAsync(string name, int id,
        CancellationToken token = default)
    { /* ... */ }
}

직렬화와 같은 작업을 포함하여 매번 제대로 하기 위해 많은 작업이 수행됩니다. 그리고 캐시 누락 시나리오에서는 여러 개의 동시 스레드, 모든 캐시 누락 가져오기, 모든 기본 데이터 가져오기, 모든 직렬화, 해당 데이터를 캐시로 보내는 것으로 끝날 수 있습니다.

이 코드를 HybridCache단순화하고 개선하려면 먼저 새 라이브러리를 추가해야 합니다.Microsoft.Extensions.Caching.Hybrid

<PackageReference Include="Microsoft.Extensions.Caching.Hybrid" Version="9.0.0" />

구현을 등록하는 HybridCache 것처럼 서비스를 등록합니다.IDistributedCache

services.AddHybridCache(); // Not shown: optional configuration API.

이제 대부분의 캐싱 문제를 다음으로 HybridCache오프로드할 수 있습니다.

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync
        (string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // Unique key for this combination.
            async cancel => await SomeExpensiveOperationAsync(name, id, cancel),
            token: token
        );
    }
}

종속성 주입을 HybridCache 통해 추상 클래스의 구체적인 구현을 제공하지만 개발자가 API의 사용자 지정 구현을 제공할 수 있습니다. 구현은 HybridCache 동시 작업 처리를 포함하여 캐싱과 관련된 모든 것을 처리합니다. 여기서 토큰은 cancel 우리가 볼 수 있는 호출자의 취소뿐만 아니라 모든 동시 호출자의 결합된 취소를 나타냅니다. token

캡처된 변수 및 인스턴스별 콜백에서 약간의 오버헤드를 방지하기 위해 패턴을 사용하여 TState 높은 처리량 시나리오를 추가로 최적화할 수 있습니다.

public class SomeService(HybridCache cache)
{
    public async Task<SomeInformation> GetSomeInformationAsync(string name, int id, CancellationToken token = default)
    {
        return await cache.GetOrCreateAsync(
            $"someinfo:{name}:{id}", // unique key for this combination
            (name, id), // all of the state we need for the final call, if needed
            static async (state, token) =>
                await SomeExpensiveOperationAsync(state.name, state.id, token),
            token: token
        );
    }
}

HybridCache 는 Redis를 사용하는 등 보조 Out-of-process 캐싱에 대해 구성된 IDistributedCache 구현(있는 경우)을 사용합니다. 그러나 서비스가 없 IDistributedCacheHybridCache 더라도 여전히 프로세스 내 캐싱 및 "스탬피드" 보호를 제공합니다.

개체 재사용에 대한 참고 사항

사용하는 IDistributedCache일반적인 기존 코드에서는 캐시에서 개체를 검색할 때마다 역직렬화가 발생합니다. 이 동작은 각 동시 호출자가 개체의 별도 인스턴스를 가져오며 다른 인스턴스와 상호 작용할 수 없음을 의미합니다. 동일한 개체 인스턴스를 동시에 수정할 위험이 없으므로 스레드 안전성도 발생합니다.

HybridCache 많은 사용량이 기존 IDistributedCache 코드 HybridCache 에서 조정되므로 동시성 버그가 발생하지 않도록 기본적으로 이 동작을 유지합니다. 그러나 지정된 사용 사례는 기본적으로 스레드로부터 안전합니다.

  • 캐시되는 형식을 변경할 수 없는 경우
  • 코드에서 수정하지 않는 경우

이러한 경우 다음을 통해 인스턴스를 다시 사용하는 것이 안전하다는 것을 알릴 HybridCache 수 있습니다.

  • 형식을 .로 표시 sealed합니다. sealed C#의 키워드(keyword) 클래스를 상속할 수 없음을 의미합니다.
  • 특성을 적용합니다 [ImmutableObject(true)] . Yhe [ImmutableObject(true)] 특성은 개체를 만든 후에는 개체의 상태를 변경할 수 없음을 나타냅니다.

인스턴스 HybridCache 를 다시 사용하면 호출별 역직렬화와 관련된 CPU 및 개체 할당의 오버헤드를 줄일 수 있습니다. 이렇게 하면 캐시된 개체가 크거나 자주 액세스하는 시나리오에서 성능이 향상될 수 있습니다.

기타 HybridCache 기능

예: IDistributedCacheHybridCache 메서드를 사용하여 키로 제거를 RemoveKeyAsync 지원합니다.

HybridCache또한 할당을 방지하기 byte[] 위해 구현에 대한 IDistributedCache 선택적 API를 제공합니다. 이 기능은 미리 보기 버전의 및 Microsoft.Extensions.Caching.SqlServer 패키지에 Microsoft.Extensions.Caching.StackExchangeRedis 의해 구현됩니다.

직렬화는 서비스 등록의 일부로 구성되며, 호출에서 AddHybridCache 연결된 메서드 및 메서드를 통해 WithSerializer 형식별 및 .WithSerializerFactory 일반화된 직렬 변환기를 지원합니다. 기본적으로 라이브러리는 내부적으로 처리 string 하고 byte[] 다른 모든 항목에 사용 System.Text.Json 하지만 protobuf, xml 또는 기타 모든 항목을 사용할 수 있습니다.

HybridCache 는 .NET Framework 4.7.2 및 .NET Standard 2.0까지 이전 .NET 런타임을 지원합니다.

자세한 HybridCache내용은 ASP.NET Core의 HybridCache 라이브러리를 참조 하세요.

개발자 예외 페이지 개선 사항

ASP.NET Core 개발자 예외 페이지는 개발 중에 앱이 처리되지 않은 예외를 throw할 때 표시됩니다. 개발자 예외 페이지에서는 예외 및 요청에 대한 자세한 정보를 제공합니다.

미리 보기 3에는 개발자 예외 페이지에 엔드포인트 메타데이터가 추가되었습니다. ASP.NET Core는 엔드포인트 메타데이터를 사용하여 라우팅, 응답 캐싱, 속도 제한, OpenAPI 생성 등과 같은 엔드포인트 동작을 제어합니다. 다음 이미지는 개발자 예외 페이지의 섹션에 Routing 있는 새 메타데이터 정보를 보여줍니다.

개발자 예외 페이지의 새 메타데이터 정보

개발자 예외 페이지를 테스트하는 동안 삶의 질이 약간 향상되었습니다. 미리 보기 4에서 제공되었습니다.

  • 텍스트 줄 래핑이 향상되었습니다. 긴 cookies, 쿼리 문자열 값 및 메서드 이름은 더 이상 가로 브라우저 스크롤 막대를 추가하지 않습니다.
  • 최신 디자인에서 찾을 수있는 더 큰 텍스트.
  • 보다 일관된 테이블 크기입니다.

다음 애니메이션 이미지는 새 개발자 예외 페이지를 보여줍니다.

새 개발자 예외 페이지

사전 디버깅 개선 사항

사전 및 기타 키-값 컬렉션의 디버깅 표시에는 향상된 레이아웃이 있습니다. 키는 값과 연결되지 않고 디버거의 키 열에 표시됩니다. 다음 이미지는 디버거에서 사전의 이전 및 새 표시를 보여 줍니다.

이전:

이전 디버거 환경

이후:

새 디버거 환경

ASP.NET Core에는 많은 키-값 컬렉션이 있습니다. 이 향상된 디버깅 환경은 다음에 적용됩니다.

  • HTTP 헤더
  • 쿼리 문자열
  • 양식
  • Cookies
  • 데이터 보기
  • 경로 데이터
  • 기능

IIS에서 앱을 재활용하는 동안 503 수정

기본적으로 IIS가 재활용 또는 종료에 대한 알림을 받는 시점과 ANCM이 관리되는 서버에 종료를 시작하라고 지시하는 시점 사이에는 1초의 지연이 있습니다. 지연은 환경 변수를 통해 또는 처리기 설정을 통해 ANCM_shutdownDelayshutdownDelay 구성할 수 있습니다. 두 값 모두 밀리초 단위입니다. 지연은 기본 경합의 가능성을 줄이기 위해 다음과 같습니다.

  • IIS는 새 앱으로 이동하라는 요청을 큐에 대기하기 시작하지 않았습니다.
  • ANCM은 이전 앱에 들어오는 새 요청을 거부하기 시작합니다.

CPU 사용량이 더 많은 느린 컴퓨터 또는 컴퓨터는 이 값을 조정하여 503 가능성을 줄일 수 있습니다.

설정 shutdownDelay의 예:

<aspNetCore processPath="dotnet" arguments="myapp.dll" stdoutLogEnabled="false" stdoutLogFile=".logsstdout">
  <handlerSettings>
    <!-- Milliseconds to delay shutdown by.
    this doesn't mean incoming requests will be delayed by this amount,
    but the old app instance will start shutting down after this timeout occurs -->
    <handlerSetting name="shutdownDelay" value="5000" />
  </handlerSettings>
</aspNetCore>

이 수정 사항은 호스팅 번들에서 제공되는 전역적으로 설치된 ANCM 모듈에 있습니다.