.NET .NET Aspire 사용자 지정 리소스 명령
.NET .NET Aspire 앱 모델의 각 리소스는 IResource로 표현되며 분산 애플리케이션 작성기에 추가될 때, IResourceBuilder<T> 인터페이스의 제네릭 타입 매개변수입니다. 리소스 작성기 API를 사용하여 호출을 연결하고, 기본 리소스를 구성하며, 경우에 따라 리소스에 사용자 지정 명령을 추가할 수 있습니다. 사용자 지정 명령을 만드는 몇 가지 일반적인 시나리오는 데이터베이스 마이그레이션을 실행하거나 데이터베이스를 시드/재설정하는 것입니다. 이 문서에서는 캐시를 지우는 Redis 리소스에 사용자 지정 명령을 추가하는 방법을 알아봅니다.
중요하다
이러한 .NET.NET Aspire 대시보드 명령은 대시보드를 로컬로 실행하는 경우에만 사용할 수 있습니다. Azure Container Apps에서 대시보드를 실행할 때는 해당 기능을 사용할 수 없습니다.
리소스에 사용자 지정 명령 추가
먼저사용 가능한
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
namespace Aspire.Hosting;
internal static class RedisResourceBuilderExtensions
{
public static IResourceBuilder<RedisResource> WithClearCommand(
this IResourceBuilder<RedisResource> builder)
{
builder.WithCommand(
name: "clear-cache",
displayName: "Clear Cache",
executeCommand: context => OnRunClearCacheCommandAsync(builder, context),
updateState: OnUpdateResourceState,
iconName: "AnimalRabbitOff",
iconVariant: IconVariant.Filled);
return builder;
}
private static async Task<ExecuteCommandResult> OnRunClearCacheCommandAsync(
IResourceBuilder<RedisResource> builder,
ExecuteCommandContext context)
{
var connectionString = await builder.Resource.GetConnectionStringAsync() ??
throw new InvalidOperationException(
$"Unable to get the '{context.ResourceName}' connection string.");
await using var connection = ConnectionMultiplexer.Connect(connectionString);
var database = connection.GetDatabase();
await database.ExecuteAsync("FLUSHALL");
return CommandResults.Success();
}
private static ResourceCommandState OnUpdateResourceState(
UpdateCommandStateContext context)
{
var logger = context.ServiceProvider.GetRequiredService<ILogger<Program>>();
if (logger.IsEnabled(LogLevel.Information))
{
logger.LogInformation(
"Updating resource state: {ResourceSnapshot}",
context.ResourceSnapshot);
}
return context.ResourceSnapshot.HealthStatus is HealthStatus.Healthy
? ResourceCommandState.Enabled
: ResourceCommandState.Disabled;
}
}
앞의 코드는 다음과 같습니다.
- 앱 호스트 프로젝트에 표시되도록 Aspire.Hosting 네임스페이스를 공유합니다.
-
static class
이 확장 메서드를 포함할 수 있도록 하기 위함입니다. -
WithClearCommand
인터페이스를 확장하는IResourceBuilder<RedisResource>
라는 단일 확장 메서드를 정의합니다. -
WithClearCommand
메서드는clear-cache
리소스의 캐시를 지우는 Redis 명령을 등록합니다. -
WithClearCommand
메서드는IResourceBuilder<RedisResource>
인스턴스를 반환하여 체인을 허용합니다.
WithCommand
API는 리소스에 적절한 주석을 추가하며, 이는 .NET.NET Aspire 대시보드에서 사용됩니다. 대시보드는 이러한 주석을 사용하여 UI에서 명령을 렌더링합니다. 이러한 세부 정보를 너무 많이 파악하기 전에 먼저 WithCommand
메서드의 매개 변수를 이해하도록 하겠습니다.
-
name
: 호출할 명령의 이름입니다. -
displayName
: 대시보드에 표시할 명령의 이름입니다. -
executeCommand
: 명령이 호출될 때 실행해야 하는Func<ExecuteCommandContext, Task<ExecuteCommandResult>>
으로, 이곳에서 명령 논리가 구현됩니다. -
updateState
:Func<UpdateCommandStateContext, ResourceCommandState>
콜백은 대시보드에서 명령을 사용하거나 사용하지 않도록 설정하는 데 사용되는 명령의 "사용" 상태를 결정하기 위해 호출됩니다. -
iconName
: 대시보드에 표시할 아이콘의 이름입니다. 아이콘은 선택 사항이지만, 제공할 경우, 올바른 Fluent UI Blazor 아이콘 이름여야 합니다. -
iconVariant
: 대시보드에 표시할 아이콘의 변형이며 유효한 옵션은Regular
(기본값) 또는Filled
.
명령어 논리 실행
executeCommand
대리자는 명령 논리가 구현되는 위치입니다. 이 매개 변수는 Func<ExecuteCommandContext, Task<ExecuteCommandResult>>
으로 정의됩니다.
ExecuteCommandContext
다음과 같은 속성을 제공합니다.
-
ExecuteCommandContext.ServiceProvider
: 서비스를 확인하는 데 사용되는IServiceProvider
인스턴스입니다. -
ExecuteCommandContext.ResourceName
: 명령이 실행 중인 리소스 인스턴스의 이름입니다. -
ExecuteCommandContext.CancellationToken
: 명령 실행을 취소하는 데 사용되는 CancellationToken.
앞의 예제에서 executeCommand
대리자는 async
리소스의 캐시를 지우는 Redis 메서드로 구현됩니다. 이 함수는 OnRunClearCacheCommandAsync
라는 이름의 프라이빗 클래스 범위 함수에 위임하여 실제 캐시 지우기를 수행합니다. 다음 코드를 고려합니다.
private static async Task<ExecuteCommandResult> OnRunClearCacheCommandAsync(
IResourceBuilder<RedisResource> builder,
ExecuteCommandContext context)
{
var connectionString = await builder.Resource.GetConnectionStringAsync() ??
throw new InvalidOperationException(
$"Unable to get the '{context.ResourceName}' connection string.");
await using var connection = ConnectionMultiplexer.Connect(connectionString);
var database = connection.GetDatabase();
await database.ExecuteAsync("FLUSHALL");
return CommandResults.Success();
}
앞의 코드는 다음과 같습니다.
- Redis 리소스에서 연결 문자열을 검색합니다.
- Redis 인스턴스에 연결합니다.
- 데이터베이스 인스턴스를 가져옵니다.
-
FLUSHALL
명령을 실행하여 캐시를 지웁니다. - 명령이 성공했음을 나타내는
CommandResults.Success()
인스턴스를 반환합니다.
명령 상태 논리 업데이트
updateState
대리자는 명령 상태가 결정되는 위치입니다. 이 매개 변수는 Func<UpdateCommandStateContext, ResourceCommandState>
으로 정의됩니다.
UpdateCommandStateContext
다음과 같은 속성을 제공합니다.
-
UpdateCommandStateContext.ServiceProvider
: 서비스를 확인하는 데 사용되는IServiceProvider
인스턴스입니다. -
UpdateCommandStateContext.ResourceSnapshot
: 명령이 실행 중인 리소스 인스턴스의 스냅샷입니다.
변경할 수 없는 스냅샷은 리소스 인스턴스에 대한 모든 종류의 중요한 세부 정보를 노출하는 CustomResourceSnapshot
인스턴스입니다. 다음 코드를 고려합니다.
private static ResourceCommandState OnUpdateResourceState(
UpdateCommandStateContext context)
{
var logger = context.ServiceProvider.GetRequiredService<ILogger<Program>>();
if (logger.IsEnabled(LogLevel.Information))
{
logger.LogInformation(
"Updating resource state: {ResourceSnapshot}",
context.ResourceSnapshot);
}
return context.ResourceSnapshot.HealthStatus is HealthStatus.Healthy
? ResourceCommandState.Enabled
: ResourceCommandState.Disabled;
}
앞의 코드는 다음과 같습니다.
- 서비스 공급자에서 로거 인스턴스를 검색합니다.
- 리소스 스냅샷 세부 정보를 기록합니다.
- 리소스가 정상이면
ResourceCommandState.Enabled
반환합니다. 그렇지 않으면ResourceCommandState.Disabled
반환합니다.
사용자 지정 명령 테스트
사용자 지정 명령을 테스트하려면 다음 코드를 포함하도록 앱 호스트 프로젝트의 Program.cs 파일을 업데이트합니다.
var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache")
.WithClearCommand();
var apiService = builder.AddProject<Projects.AspireApp_ApiService>("apiservice");
builder.AddProject<Projects.AspireApp_Web>("webfrontend")
.WithExternalHttpEndpoints()
.WithReference(cache)
.WaitFor(cache)
.WithReference(apiService)
.WaitFor(apiService);
builder.Build().Run();
앞의 코드는 WithClearCommand
확장 메서드를 호출하여 사용자 지정 명령을 Redis 리소스에 추가합니다. 앱을 실행하고 .NET.NET Aspire 대시보드로 이동합니다.
Redis 리소스 아래에 나열된 사용자 지정 명령이 표시됩니다. 대시보드의 리소스 페이지에서 작업 열 아래의 줄임표 단추를 선택합니다.
앞의 이미지는 리소스에 추가된 Redis 명령을 보여줍니다. 아이콘은 토끼가 교차할 때 표시되어 의존 자원의 속도가 지워지고 있음을 나타냅니다.
리소스의 캐시를 지우려면 Redis 명령을 선택합니다. 명령이 성공적으로 실행되고 캐시가 지워져야 합니다.
참고 자료
.NET Aspire