Orleans e integração do .NET Aspire

.NET Aspire oferece uma abordagem simplificada para construir aplicações cloud-native com suporte integrado para Orleans. A partir de Orleans 8.0, pode usar Aspire para orquestrar o seu cluster Orleans, gerir recursos de backup (como Redis ou Armazenamento do Azure) e configurar automaticamente a descoberta de serviços, observabilidade e verificações de saúde.

Visão geral

Orleans integração com .NET Aspire utiliza o pacote Aspire.Hosting.Orleans no seu projeto AppHost. Este pacote fornece métodos de extensão para:

  • Defina Orleans como um recurso distribuído
  • Configurar fornecedores de clustering (Redis, Armazenamento do Azure, ADO.NET)
  • Configurar fornecedores de armazenamento de grãos
  • Configurar fornecedores de lembretes
  • Configurar os fornecedores de diretórios Grain
  • Modelos de silo e relações com clientes

Pré-requisitos

Antes de usar Orleans com Aspire, certifique-se de que tem:

Pacotes obrigatórios

A sua solução precisa das seguintes referências de pacotes:

Projeto AppHost

<ItemGroup>
  <PackageReference Include="Aspire.Hosting.AppHost" Version="13.1.3" />
  <PackageReference Include="Aspire.Hosting.Orleans" Version="13.1.3" />
  <PackageReference Include="Aspire.Hosting.Redis" Version="13.1.3" />
</ItemGroup>

Orleans Projeto do Silo

<ItemGroup>
  <PackageReference Include="Microsoft.Orleans.Server" Version="10.1.0" />
  <PackageReference Include="Microsoft.Orleans.Clustering.Redis" Version="10.1.0" />
  <PackageReference Include="Aspire.StackExchange.Redis" Version="13.2.4" />
</ItemGroup>

Orleans Projeto do cliente (se separado do silo)

<ItemGroup>
  <PackageReference Include="Microsoft.Orleans.Client" Version="10.1.0" />
  <PackageReference Include="Microsoft.Orleans.Clustering.Redis" Version="10.1.0" />
  <PackageReference Include="Aspire.StackExchange.Redis" Version="13.2.4" />
</ItemGroup>

Configurar o AppHost

O projeto AppHost orquestra o seu Orleans cluster e as suas dependências.

Cluster básico Orleans com clustering do Redis

public static void BasicOrleansCluster(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    // Add Redis for Orleans clustering
    var redis = builder.AddRedis("orleans-redis");

    // Define the Orleans resource with Redis clustering
    var orleans = builder.AddOrleans("cluster")
        .WithClustering(redis);

    // Add the Orleans silo project
    builder.AddProject<Projects.Silo>("silo")
        .WithReference(orleans)
        .WaitFor(redis)
        .WithReplicas(3);

    builder.Build().Run();
}

Orleans com armazenamento de cereais e lembretes

public static void OrleansWithStorageAndReminders(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    var redis = builder.AddRedis("orleans-redis");

    var orleans = builder.AddOrleans("cluster")
        .WithClustering(redis)
        .WithGrainStorage("Default", redis)
        .WithGrainStorage("PubSubStore", redis)
        .WithReminders(redis);

    builder.AddProject<Projects.Silo>("silo")
        .WithReference(orleans)
        .WaitFor(redis)
        .WithReplicas(3);

    builder.Build().Run();
}

Separe silo e projetos de clientes

Quando o seu Orleans cliente corre num processo separado (como uma interface web), use o .AsClient() método:

public static void SeparateSiloAndClient(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    var redis = builder.AddRedis("orleans-redis");

    var orleans = builder.AddOrleans("cluster")
        .WithClustering(redis)
        .WithGrainStorage("Default", redis);

    // Backend Orleans silo cluster
    var silo = builder.AddProject<Projects.Silo>("backend")
        .WithReference(orleans)
        .WaitFor(redis)
        .WithReplicas(5);

    // Frontend web project as Orleans client
    builder.AddProject<Projects.Client>("frontend")
        .WithReference(orleans.AsClient())  // Client-only reference
        .WaitFor(silo);

    builder.Build().Run();
}

Configurar o projeto de silo Orleans

No seu Orleans projeto de silo, configure Orleans para usar os recursos fornecidos pelo Aspire.

public static void BasicSiloConfiguration(string[] args)
{
    var builder = Host.CreateApplicationBuilder(args);

    // Add Aspire service defaults (OpenTelemetry, health checks, etc.)
    builder.AddServiceDefaults();

    // Add the Aspire Redis client for Orleans
    builder.AddKeyedRedisClient("orleans-redis");

    // Configure Orleans - Aspire injects all configuration automatically
    builder.UseOrleans();

    builder.Build().Run();
}

Sugestão

Ao usar .NET Aspire, o UseOrleans sem parâmetros é normalmente tudo o que precisas. Aspire injeta Orleans configuração (ID de cluster, ID de serviço, endpoints e definições do fornecedor) através de variáveis de ambiente que Orleans lê automaticamente. Só é necessária a sobrecarga UseOrleans(siloBuilder => {...}) de delegados quando precisas de uma configuração manual adicional para além do que é proporcionado por Aspire.

Importante

Deve chamar o método apropriado AddKeyed* (como AddKeyedRedisClient, AddKeyedAzureTableClient, ou AddKeyedAzureBlobClient) para registrar o recurso de suporte no contentor de injeção de dependências. Orleans Os provedores procuram os recursos pelo nome do serviço identificado pela chave — se saltar este passo, Orleans não conseguirá resolver o recurso e lançará um erro de resolução de dependências em tempo de execução. Isto aplica-se a todos os recursos geridos usados com OrleansAspire.

Configurar com string de ligação explícita

Se precisar de controlo explícito sobre a cadeia de ligação, pode lê-la a partir da configuração:

public static void ExplicitConnectionConfiguration(string[] args)
{
    var builder = Host.CreateApplicationBuilder(args);

    builder.AddServiceDefaults();
    builder.AddKeyedRedisClient("orleans-redis");

    builder.UseOrleans(siloBuilder =>
    {
        var redisConnectionString = builder.Configuration.GetConnectionString("orleans-redis");

        siloBuilder.UseRedisClustering(options =>
        {
            options.ConfigurationOptions =
                ConfigurationOptions.Parse(redisConnectionString!);
        });

        siloBuilder.AddRedisGrainStorageAsDefault(options =>
        {
            options.ConfigurationOptions =
                ConfigurationOptions.Parse(redisConnectionString!);
        });
    });

    builder.Build().Run();
}

Configurar o Orleans projeto cliente

Para projetos de cliente separados, configure o Orleans cliente de forma semelhante:

public static void BasicClientConfiguration(string[] args)
{
    var builder = Host.CreateApplicationBuilder(args);

    builder.AddServiceDefaults();
    builder.AddKeyedRedisClient("orleans-redis");

    // Configure Orleans client - Aspire injects clustering configuration automatically
    builder.UseOrleansClient();

    builder.Build().Run();
}

Referência de métodos de extensão AppHost

O Aspire.Hosting.Orleans pacote fornece estes métodos de extensão:

Métodos centrais

Método Description
builder.AddOrleans(name) Adiciona um Orleans recurso à aplicação distribuída com o nome especificado.
.WithClusterId(id) Define o Orleans ClusterId. Aceita uma cadeia de caracteres ou ParameterResource. Se não especificado, um ID único é gerado automaticamente.
.WithServiceId(id) Define o Orleans ServiceId. Aceita uma cadeia de caracteres ou ParameterResource. Se não especificado, um ID único é gerado automaticamente.
.AsClient() Devolve uma referência ao recurso Orleans apenas para o cliente (não inclui capacidades de silo).
project.WithReference(orleans) Adiciona a Orleans referência de recurso a um projeto, permitindo a injeção de configuração.

Observação

Quando configura um recurso de suporte usando .WithClustering(resource), .WithGrainStorage(name, resource), ou métodos semelhantes, o Orleans recurso inclui automaticamente uma referência a esse recurso de apoio. Não precisa de ligar .WithReference() separadamente para cada recurso de apoio — apenas .WithReference(orleans) é obrigatório. No entanto, deve usar o recurso de apoio .WaitFor() para garantir que está pronto antes de começar o silo.

Clusterização

Método Description
.WithClustering(resource) Configura Orleans o clustering para usar o recurso especificado (Redis, Armazenamento do Azure, Cosmos DB, etc.).
.WithDevelopmentClustering() Configura clustering em memória, com um único host, apenas para desenvolvimento local. Não é adequado para produção.

Armazenamento de cereais

Método Description
.WithGrainStorage(name, resource) Configura um fornecedor de armazenamento de grãos nomeado usando o recurso especificado.
.WithMemoryGrainStorage(name) Configura o armazenamento de grão em memória para o nome especificado. Os dados perdem-se no reinício do silo.

Lembretes

Método Description
.WithReminders(resource) Configura o Orleans serviço de lembrete usando o recurso especificado.
.WithMemoryReminders() Configura lembretes em memória para desenvolvimento. Os lembretes perdem-se no reinício do silo.

Serviço de streaming

Método Description
.WithStreaming(name, resource) Configura um fornecedor de fluxo nomeado usando o recurso especificado (por exemplo, Armazenamento de Filas do Azure).
.WithMemoryStreaming(name) Configura o streaming em memória para desenvolvimento.
.WithBroadcastChannel(name) Configura um fornecedor de canal de difusão com o nome especificado.

Diretório de grãos

Método Description
.WithGrainDirectory(name, resource) Configura um diretório grain nomeado usando o recurso especificado.

Padrão de configurações padrão de serviço

Aspire utiliza um padrão de projeto ServiceDefaults para partilhar configurações comuns em todos os projetos. Para Orleans, isto normalmente inclui:

Configuração do OpenTelemetry

public static IHostApplicationBuilder AddServiceDefaults(
    this IHostApplicationBuilder builder)
{
    builder.ConfigureOpenTelemetry();
    builder.AddDefaultHealthChecks();
    
    return builder;
}

public static IHostApplicationBuilder ConfigureOpenTelemetry(
    this IHostApplicationBuilder builder)
{
    builder.Logging.AddOpenTelemetry(logging =>
    {
        logging.IncludeFormattedMessage = true;
        logging.IncludeScopes = true;
    });

    builder.Services.AddOpenTelemetry()
        .WithMetrics(metrics =>
        {
            metrics.AddAspNetCoreInstrumentation()
                .AddHttpClientInstrumentation()
                .AddRuntimeInstrumentation()
                .AddMeter("Microsoft.Orleans");  // Orleans metrics
        })
        .WithTracing(tracing =>
        {
            tracing.AddAspNetCoreInstrumentation()
                .AddHttpClientInstrumentation()
                .AddSource("Microsoft.Orleans.Runtime")
                .AddSource("Microsoft.Orleans.Application");
        });

    return builder;
}

Armazenamento do Azure com Aspire

Pode usar os recursos do Armazenamento do Azure para Orleans clusterização e persistência:

public static void AzureStorageWithAspire(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    // Add Azure Storage for Orleans
    var storage = builder.AddAzureStorage("orleans-storage")
        .RunAsEmulator();  // Use Azurite emulator for local development

    var tables = storage.AddTables("orleans-tables");
    var blobs = storage.AddBlobs("orleans-blobs");

    var orleans = builder.AddOrleans("cluster")
        .WithClustering(tables)
        .WithGrainStorage("Default", blobs)
        .WithReminders(tables);

    builder.AddProject<Projects.Silo>("silo")
        .WithReference(orleans)
        .WaitFor(storage)
        .WithReplicas(3);

    builder.Build().Run();
}

Configuração de desenvolvimento vs. produção

Aspire Facilita a alternância entre configurações de desenvolvimento e produção:

Desenvolvimento local (usando emuladores)

public static void LocalDevelopment(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    var redis = builder.AddRedis("orleans-redis");
    // Redis container runs automatically during development

    var orleans = builder.AddOrleans("cluster")
        .WithClustering(redis);

    // ...
}

Produção (usando serviços geridos)

public static void ProductionConfig(string[] args)
{
    var builder = DistributedApplication.CreateBuilder(args);

    // Use existing Azure Cache for Redis
    var redis = builder.AddConnectionString("orleans-redis");

    var orleans = builder.AddOrleans("cluster")
        .WithClustering(redis);

    // ...
}

Controlos sanitários

Aspire Configura automaticamente os endpoints de verificação de saúde. Pode adicionar exames de saúde específicos para Orleans:

public static void ConfigureHealthChecks(IHostApplicationBuilder builder)
{
    builder.Services.AddHealthChecks()
        .AddCheck<GrainHealthCheck>("orleans-grains")
        .AddCheck<SiloHealthCheck>("orleans-silo");
}

Melhores práticas

  1. Use ServiceDefaults: Partilhe configurações comuns (OpenTelemetry, verificações de saúde) em todos os projetos que utilizam um projeto ServiceDefaults.

  2. Aguarde dependências: Use .WaitFor() sempre para garantir que os recursos de backup (Redis, bases de dados) estejam prontos antes Orleans de começarem os silos.

  3. Configurar réplicas: Usar .WithReplicas() para executar múltiplas instâncias de silo para tolerância a falhas e escalabilidade.

  4. Projetos de cliente separados: Para frontends web, use .AsClient() para configurar Orleans o modo apenas cliente.

  5. Use emuladores para desenvolvimento: Aspire pode executar Redis, Armazenamento do Azure (Azurite) e outras dependências localmente usando containers.

  6. Ative o rastreamento distribuído: Configure o OpenTelemetry com Orleans nomes de origem para rastrear chamadas de grain através do cluster.

Consulte também

A integração .NET Aspire foi introduzida no Orleans 8.0. Para a versão Orleans 7.0, ainda pode implementar em ambientes Aspire-orquestrados, mas o pacote Aspire.Hosting.Orleans dedicado e os seus métodos de extensão não estão disponíveis.

Considere atualizar para Orleans a versão 8.0 ou posterior para tirar partido das Aspire funcionalidades de integração.

A integração .NET Aspire está disponível em Orleans 8.0 e posteriores. Orleans 3.x não suporta .NET Aspire.