integração .NET AspireAzure Event Hubs
Azure Event Hubs é um serviço nativo de streaming de dados na nuvem que pode transmitir milhões de eventos por segundo, com baixa latência, de qualquer fonte para qualquer destino. A integração .NET AspireAzure Event Hubs permite que você se conecte a instâncias Azure Event Hubs a partir de seus aplicativos .NET.
Integração de hospedagem
O .NET.NET AspireAzure Event Hubs modelo de integração de hospedagem modela os vários recursos do Hub de Eventos como dos seguintes tipos:
- AzureEventHubsResource: representa um recurso de Azure Event Hubs de nível superior, usado para representar coleções de hubs e as informações de conexão com o recurso de Azure subjacente.
- AzureEventHubResource: representa um único recurso do Hub de Eventos.
- AzureEventHubsEmulatorResource: representa um emulador Azure Event Hubs como um recurso de contêiner.
- AzureEventHubConsumerGroupResource: representa um grupo de consumidores dentro de um recurso do Hub de Eventos.
Para acessar esses tipos e APIs para expressá-los no projeto de host do seu aplicativo, instale o pacote NuGet 📦Aspire.Hosting.Azure.EventHubs.
dotnet add package Aspire.Hosting.Azure.EventHubs
Para obter mais informações, consulte dotnet add package ou Gerenciar dependências de pacotes em .NET aplicações.
Adicionar um recurso Azure Event Hubs
Para adicionar um AzureEventHubsResource ao projeto de host do aplicativo, chame o método AddAzureEventHubs fornecendo um nome e, em seguida, chame AddHub:
var builder = DistributedApplication.CreateBuilder(args);
var eventHubs = builder.AddAzureEventHubs("event-hubs");
eventHubs.AddHub("messages");
builder.AddProject<Projects.ExampleService>()
.WithReference(eventHubs);
// After adding all resources, run the app...
Quando você adiciona um recurso Azure Event Hubs ao host do aplicativo, ele expõe outras APIs úteis para adicionar recursos do Hub de Eventos, grupos de consumidores, expressar configuração de provisionamento explícito e habilita o uso do emulador de Azure Event Hubs. O código anterior adiciona um recurso Azure Event Hubs chamado event-hubs
e um Hub de Eventos chamado messages
ao projeto de host do aplicativo. O método WithReference passa as informações de conexão para o projeto ExampleService
.
Importante
Quando você chama AddAzureEventHubs, ele chama implicitamente AddAzureProvisioning(IDistributedApplicationBuilder)— o que adiciona suporte para gerar recursos Azure dinamicamente durante a inicialização do aplicativo. O aplicativo deve configurar a assinatura e o local apropriados. Para obter mais informações, consulte Provisionamento local: Configuração
Gerado provisionamento em Bicep
Se você é novo em Bicep, é uma linguagem específica do domínio para definir recursos Azure. Com .NET.NET Aspire, você não precisa escrever Bicep manualmente; as APIs de provisionamento geram Bicep para você. Quando você publica seu aplicativo, o Bicep gerado é exibido junto com o arquivo de manifesto. Quando você adiciona um recurso Azure Event Hubs, o seguinte Bicep é gerado:
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location
param sku string = 'Standard'
param principalType string
param principalId string
resource event_hubs 'Microsoft.EventHub/namespaces@2024-01-01' = {
name: take('event_hubs-${uniqueString(resourceGroup().id)}', 256)
location: location
sku: {
name: sku
}
tags: {
'aspire-resource-name': 'event-hubs'
}
}
resource event_hubs_AzureEventHubsDataOwner 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(event_hubs.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f526a384-b230-433a-b45c-95f59c4a2dec'))
properties: {
principalId: principalId
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f526a384-b230-433a-b45c-95f59c4a2dec')
principalType: principalType
}
scope: event_hubs
}
resource messages 'Microsoft.EventHub/namespaces/eventhubs@2024-01-01' = {
name: 'messages'
parent: event_hubs
}
output eventHubsEndpoint string = event_hubs.properties.serviceBusEndpoint
O Bicep anterior é um módulo que provisiona um recurso Azure Event Hubs com os seguintes padrões:
-
location
: o local do grupo de recursos. -
sku
: o SKU do recurso Hubs de Eventos, padrão éStandard
. -
principalId
: o ID principal do recurso Hubs de Eventos. -
principalType
: O tipo principal do recurso Hubs de Eventos. -
event_hubs
: O recurso namespace dos Event Hubs. -
event_hubs_AzureEventHubsDataOwner
: o proprietário do recurso dos Hubs de Eventos, com base na função internaAzure Event Hubs Data Owner
integrada. Para obter mais informações, consulte Azure Event Hubs Proprietário de Dados. -
messages
: o recurso do Hub de Eventos. -
eventHubsEndpoint
: O ponto de extremidade do recurso Hubs de Eventos.
O Bicep gerado é um ponto de partida e pode ser personalizado para atender aos seus requisitos específicos.
Personalizar a infraestrutura de provisionamento
Todos os recursos .NET AspireAzure são subclasses do tipo AzureProvisioningResource. Esse tipo permite a personalização do Bicep gerado, fornecendo uma API fluente para a configuração dos recursos Azure usando a API ConfigureInfrastructure<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure>). Por exemplo, você pode configurar o kind
, consistencyPolicy
, locations
e muito mais. O exemplo a seguir demonstra como personalizar o recurso de AzureAzure Cosmos DB:
builder.AddAzureEventHubs("event-hubs")
.ConfigureInfrastructure(infra =>
{
var eventHubs = infra.GetProvisionableResources()
.OfType<EventHubsNamespace>()
.Single();
eventHubs.Sku = new EventHubsSku()
{
Name = EventHubsSkuName.Premium,
Tier = EventHubsSkuTier.Premium,
Capacity = 7,
};
eventHubs.PublicNetworkAccess = EventHubsPublicNetworkAccess.SecuredByPerimeter;
eventHubs.Tags.Add("ExampleKey", "Example value");
});
O código anterior:
- Encadeia uma chamada à API ConfigureInfrastructure:
- O parâmetro
infra
é uma instância do tipo AzureResourceInfrastructure. - Os recursos provisionáveis são recuperados chamando o método GetProvisionableResources().
- O único recurso EventHubsNamespace é recuperado.
- A propriedade EventHubsNamespace.Sku é atribuída a uma nova instância de EventHubsSku com o nome e camada de
Premium
e umCapacity
de7
. - A propriedade PublicNetworkAccess é atribuída a
SecuredByPerimeter
. - Uma tag é adicionada ao recurso Hubs de Eventos com uma chave de
ExampleKey
e um valor deExample value
.
- O parâmetro
Há muitas outras opções de configuração disponíveis para personalizar o recurso de recurso dos Hubs de Eventos. Para obter mais informações, consulte Azure.Provisioning.PostgreSql. Para obter mais informações, consulte a personalização de Azure.Provisioning
.
Conectar-se a um namespace Azure Event Hubs existente
Você pode ter um namespace Azure Event Hubs existente ao qual deseja se conectar. Em vez de representar um novo recurso de Azure Event Hubs, você pode adicionar uma cadeia de conexão ao host do aplicativo. Para adicionar uma conexão a um namespace Azure Event Hubs existente, chame o método AddConnectionString:
var builder = DistributedApplication.CreateBuilder(args);
var eventHubs = builder.AddConnectionString("event-hubs");
builder.AddProject<Projects.WebApplication>("web")
.WithReference(eventHubs);
// After adding all resources, run the app...
Nota
As cadeias de conexão são usadas para representar uma ampla gama de informações de conexão, incluindo conexões de banco de dados, agentes de mensagens, URIs de ponto de extremidade e outros serviços. Em .NET.NET Aspire nomenclatura, o termo "cadeia de conexão" é usado para representar qualquer tipo de informação de conexão.
A cadeia de conexão é configurada na configuração do host do aplicativo, normalmente em Segredos do Usuário, na seção ConnectionStrings
. O host do aplicativo injeta essa cadeia de conexão como uma variável de ambiente em todos os recursos dependentes, por exemplo:
{
"ConnectionStrings": {
"event-hubs": "{your_namespace}.servicebus.windows.net"
}
}
O recurso dependente pode acessar a cadeia de conexão injetada chamando o método GetConnectionString e passando o nome da conexão como o parâmetro, nesse caso "event-hubs"
. A API GetConnectionString
é uma abreviação de IConfiguration.GetSection("ConnectionStrings")[name]
.
Adicionar grupo de consumidores do Hub de Eventos
Para adicionar um grupo de consumidores, encadeie uma chamada no IResourceBuilder<AzureEventHubsResource>
para a API de AddConsumerGroup.
var builder = DistributedApplication.CreateBuilder(args);
var eventHubs = builder.AddAzureEventHubs("event-hubs");
var messages = eventHubs.AddHub("messages");
messages.AddConsumerGroup("messagesConsumer");
builder.AddProject<Projects.ExampleService>()
.WithReference(eventHubs);
// After adding all resources, run the app...
Quando você chama AddConsumerGroup
, ele configura seu recurso do Hub de Eventos messages
para ter um grupo de consumidores chamado messagesConsumer
. O grupo de consumidores é criado no namespace Azure Event Hubs representado pelo AzureEventHubsResource
que você adicionou anteriormente. Para obter mais informações, consulte Azure Event Hubs: Grupos de consumidores.
Adicionar recurso do emulador Azure Event Hubs
A integração de hospedagem .NET AspireAzure Event Hubs dá suporte à execução do recurso hubs de eventos como um emulador localmente, com base na imagem de contêiner mcr.microsoft.com/azure-messaging/eventhubs-emulator/latest
. Isso é benéfico para situações em que você deseja executar o recurso dos Hubs de Eventos localmente para fins de desenvolvimento e teste, evitando a necessidade de provisionar um recurso Azure ou se conectar a um servidor Azure Event Hubs existente.
Para executar o recurso hubs de eventos como um emulador, chame o método RunAsEmulator:
var builder = DistributedApplication.CreateBuilder(args);
var eventHubs = builder.AddAzureEventHubs("event-hubs")
.RunAsEmulator();
eventHubs.AddHub("messages");
var exampleProject = builder.AddProject<Projects.ExampleProject>()
.WithReference(eventHubs);
// After adding all resources, run the app...
O código anterior configura um recurso de Azure Event Hubs a ser executado localmente em um contêiner. Para obter mais informações, consulte o Emulador Azure Event Hubs.
Configurar o contêiner do emulador dos Hubs de Eventos
Há várias configurações disponíveis para recursos de contêiner, por exemplo, você pode configurar as portas do contêiner, montagens com ligação de dados, volumes de dados ou fornecer uma configuração JSON holística que substitui tudo.
Configurar a porta de host do contêiner do emulador de Hubs de Eventos
Por padrão, sendo configurado por .NET.NET Aspire, o contêiner do emulador dos Hubs de Eventos expõe os seguintes pontos de extremidade:
Ponto de extremidade | Imagem | Porta de contêiner | Porta do host |
---|---|---|---|
emulator |
mcr.microsoft.com/azure-messaging/eventhubs-emulator/latest |
5672 | dinâmico |
A porta que está sendo utilizada para escuta é dinâmica por padrão. Quando o contêiner é iniciado, a porta é mapeada para uma porta aleatória no computador host. Para configurar a porta do ponto de extremidade, encadeia chamadas no construtor de recursos de contêiner fornecido pelo método RunAsEmulator
e, em seguida, o WithHostPort(IResourceBuilder<AzureEventHubsEmulatorResource>, Nullable<Int32>) conforme mostrado no exemplo a seguir:
var builder = DistributedApplication.CreateBuilder(args);
var eventHubs = builder.AddAzureEventHubs("event-hubs")
.RunAsEmulator(emulator =>
{
emulator.WithHostPort(7777);
});
eventHubs.AddHub("messages");
builder.AddProject<Projects.ExampleService>()
.WithReference(eventHubs);
// After adding all resources, run the app...
O código anterior configura o ponto de extremidade existente emulator
do contêiner do emulador de eventos Azure para escutar a porta 7777
. A porta do contêiner do emulador de eventos do Azure é mapeada para a porta de host, conforme mostrado na tabela a seguir:
Nome do ponto de extremidade | Mapeamento de porta (container:host ) |
---|---|
emulator |
5672:7777 |
Adicionar emulador de Hubs de Eventos com volume de dados
Para adicionar um volume de dados ao recurso emulador dos Hubs de Eventos, chame o método WithDataVolume no recurso emulador dos Hubs de Eventos:
var builder = DistributedApplication.CreateBuilder(args);
var eventHubs = builder.AddAzureEventHubs("event-hubs")
.RunAsEmulator(emulator =>
{
emulator.WithDataVolume();
});
eventHubs.AddHub("messages");
builder.AddProject<Projects.ExampleService>()
.WithReference(eventHubs);
// After adding all resources, run the app...
O volume de dados é utilizado para persistir os dados do emulador do Event Hubs além do ciclo de vida de seu contêiner. O volume de dados é montado no caminho /data
no contêiner. Um nome é gerado aleatoriamente, a menos que você forneça um conjunto do parâmetro name
. Para obter mais informações sobre volumes de dados e detalhes sobre por que eles são preferidos em vez de montagens de ligação , consulte os documentos Docker: Volumes.
Adicionar emulador de Hubs de Eventos com montagem de associação de dados
Adicione uma montagem de vinculação ao contêiner do emulador de Hubs de Eventos, encadeie uma chamada à API WithDataBindMount, conforme mostrado no exemplo a seguir:
var builder = DistributedApplication.CreateBuilder(args);
var eventHubs = builder.AddAzureEventHubs("event-hubs")
.RunAsEmulator(emulator =>
{
emulator.WithDataBindMount("/path/to/data");
});
eventHubs.AddHub("messages");
builder.AddProject<Projects.ExampleService>()
.WithReference(eventHubs);
// After adding all resources, run the app...
Importante
Montagens de ligação de dados têm funcionalidade limitada em comparação com volumes , os quais oferecem melhor desempenho, portabilidade e segurança, o que os torna mais adequados para ambientes de produção. No entanto, os bind mounts permitem acesso direto e modificação de arquivos no sistema host, sendo ideal para desenvolvimento e teste onde são necessárias alterações em tempo real.
As montagens de associação de dados dependem do sistema de arquivos do computador host para persistir os dados de recurso do emulador Azure Event Hubs entre reinicializações de contêiner. A montagem do vínculo de dados está montada no caminho /path/to/data
na máquina host dentro do contêiner. Para obter mais informações sobre montagens de vínculo de dados, consulte a documentação Docker: Montagens de vínculo.
Configurar a configuração do contêiner do emulador dos Hubs de Eventos JSON
O contêiner do emulador dos Hubs de Eventos é executado com um arquivo padrão de config.json. Você pode substituir esse arquivo inteiramente ou atualizar a configuração de JSON com uma versão JsonNode da configuração.
Para fornecer um arquivo de configuração de JSON personalizado, chame o método WithConfigurationFile(IResourceBuilder<AzureEventHubsEmulatorResource>, String):
var builder = DistributedApplication.CreateBuilder(args);
var eventHubs = builder.AddAzureEventHubs("event-hubs")
.RunAsEmulator(emulator =>
{
emulator.WithConfigurationFile("./messaging/custom-config.json");
});
eventHubs.AddHub("messages");
builder.AddProject<Projects.ExampleService>()
.WithReference(eventHubs);
// After adding all resources, run the app...
O código anterior configura o contêiner do emulador de Hubs de Eventos para usar um arquivo de configuração de JSON personalizado localizado em ./messaging/custom-config.json
. Isso será montado no caminho /Eventhubs_Emulator/ConfigFiles/Config.json
no contêiner, como um arquivo em modo somente leitura. Para, em vez disso, substituir propriedades específicas na configuração padrão, chame o método WithConfiguration(IResourceBuilder<AzureEventHubsEmulatorResource>, Action<JsonNode>):
var builder = DistributedApplication.CreateBuilder(args);
var eventHubs = builder.AddAzureEventHubs("event-hubs")
.RunAsEmulator(emulator =>
{
emulator.WithConfiguration(
(JsonNode configuration) =>
{
var userConfig = configuration["UserConfig"];
var ns = userConfig["NamespaceConfig"][0];
var firstEntity = ns["Entities"][0];
firstEntity["PartitionCount"] = 5;
});
});
eventHubs.AddHub("messages");
builder.AddProject<Projects.ExampleService>()
.WithReference(eventHubs);
// After adding all resources, run the app...
O código anterior recupera o nó UserConfig
da configuração padrão. Em seguida, atualiza o PartitionCount
da primeira entidade para um 5
.
Verificações de integridade das integrações de hospedagem
A integração de hospedagem do Azure Event Hubs adiciona automaticamente uma verificação de integridade para o recurso Event Hubs. A verificação de integridade confirma se os Hubs de Eventos estão em execução e se é possível estabelecer uma conexão com eles.
A integração de hospedagem depende do 📦 AspNetCore.HealthChecks.Azure. Messaging.EventHubs pacote NuGet.
Integração com o Client
Para começar a usar a integração do cliente .NET AspireAzure Event Hubs, instale o pacote NuGet 📦Aspire.Azure.Messaging.EventHubs no projeto que consome o cliente, isto é, o projeto para o aplicativo que utiliza o cliente Event Hubs.
dotnet add package Aspire.Azure.Messaging.EventHubs
Tipos de cliente dos Hubs de Eventos com suporte
Os seguintes clientes do Hub de Eventos são compatíveis com a biblioteca, juntamente com suas opções e classes de configurações correspondentes:
Os tipos de cliente são do SDK Azure para .NET, assim como as classes de opções correspondentes. As classes de configurações são fornecidas pelo .NET.NET Aspire. As classes de configurações são usadas para configurar as instâncias do cliente.
Adicionar um cliente produtor dos Hubs de Eventos
No arquivo Program.cs do projeto cliente, chame o método de extensão AddAzureEventHubProducerClient em qualquer IHostApplicationBuilder para registrar um EventHubProducerClient para uso através do contêiner de injeção de dependência. O método usa um parâmetro de nome de conexão.
builder.AddAzureEventHubProducerClient(connectionName: "event-hubs");
Gorjeta
O parâmetro connectionName
deve corresponder ao nome usado ao adicionar o recurso hubs de eventos no projeto de host do aplicativo. Para obter mais informações, consulte Adicionar um recurso Azure Event Hubs.
Depois de adicionar o EventHubProducerClient
, você pode recuperar a instância do cliente usando a injeção de dependência. Por exemplo, para recuperar o objeto da fonte de dados de um serviço de exemplo, defina-o como um parâmetro de construtor e verifique se a classe ExampleService
está registrada com o contêiner de injeção de dependência:
public class ExampleService(EventHubProducerClient client)
{
// Use client...
}
Para obter mais informações, consulte:
-
Azure. A documentação do Messaging.EventHubs para exemplos de como usar o
EventHubProducerClient
. - injeção de dependência em .NET para obter detalhes sobre a injeção de dependência.
APIs adicionais a serem consideradas
A integração do cliente fornece APIs adicionais para configurar instâncias de cliente. Quando você precisar registrar um cliente dos Hubs de Eventos, considere as seguintes APIs:
Todas as APIs mencionadas incluem parâmetros opcionais para configurar as instâncias do cliente.
Adicionar cliente produtor de Hubs de Eventos com chave
Pode haver situações em que você deseja registrar várias instâncias de EventHubProducerClient
com nomes de conexão diferentes. Para registrar clientes chave dos Hubs de Eventos, chame o método AddKeyedAzureServiceBusClient:
builder.AddKeyedAzureEventHubProducerClient(name: "messages");
builder.AddKeyedAzureEventHubProducerClient(name: "commands");
Importante
Ao usar serviços com chave, espera-se que o recurso dos Hubs de Eventos configure dois hubs nomeados, um para o messages
e outro para o commands
.
Em seguida, você pode recuperar as instâncias do cliente usando a injeção de dependência. Por exemplo, para recuperar os clientes de um serviço:
public class ExampleService(
[KeyedService("messages")] EventHubProducerClient messagesClient,
[KeyedService("commands")] EventHubProducerClient commandsClient)
{
// Use clients...
}
Para obter mais informações, consulte Serviços chaveados no .NET.
APIs com chave adicional a serem consideradas
A integração do cliente fornece APIs adicionais para configurar instâncias de cliente com chave. Quando você precisar registrar um cliente de Hubs de Eventos com chave, considere as seguintes APIs:
Todas as APIs mencionadas incluem parâmetros opcionais para configurar as instâncias do cliente.
Configuração
A biblioteca de .NET AspireAzure Event Hubs fornece várias opções para configurar a conexão Azure Event Hubs com base nos requisitos e convenções do seu projeto. É necessário fornecer um FullyQualifiedNamespace
ou um ConnectionString
.
Usar uma string de conexão
Ao usar uma cadeia de conexão da seção de configuração ConnectionStrings
, forneça o nome da cadeia de conexão ao chamar builder.AddAzureEventHubProducerClient()
e outros clientes dos Hubs de Eventos com suporte. Neste exemplo, a cadeia de conexão não inclui a propriedade EntityPath
, portanto, a propriedade EventHubName
deve ser definida no retorno de chamada de configurações:
builder.AddAzureEventHubProducerClient(
"event-hubs",
static settings =>
{
settings.EventHubName = "MyHub";
});
E, em seguida, as informações de conexão serão recuperadas da seção de configuração ConnectionStrings
. Há suporte para dois formatos de conexão:
Namespace totalmente qualificado (FQN)
A abordagem recomendada é usar um namespace totalmente qualificado, que funciona com a propriedade AzureMessagingEventHubsSettings.Credential para estabelecer uma conexão. Se nenhuma credencial estiver configurada, o DefaultAzureCredential será usado.
{
"ConnectionStrings": {
"event-hubs": "{your_namespace}.servicebus.windows.net"
}
}
Cadeia de conexão
Como alternativa, use uma cadeia de conexão:
{
"ConnectionStrings": {
"event-hubs": "Endpoint=sb://mynamespace.servicebus.windows.net/;SharedAccessKeyName=accesskeyname;SharedAccessKey=accesskey;EntityPath=MyHub"
}
}
Usar provedores de configuração
A biblioteca de .NET AspireAzure Event Hubs dá suporte a Microsoft.Extensions.Configuration. Ele carrega o AzureMessagingEventHubsSettings
e as Opções associadas, por exemplo, EventProcessorClientOptions
, da configuração usando o prefixo de chave Aspire:Azure:Messaging:EventHubs:
, seguido pelo nome do cliente específico em uso. Por exemplo, considere o appsettings.json que configura algumas opções de um EventProcessorClient
.
{
"Aspire": {
"Azure": {
"Messaging": {
"EventHubs": {
"EventProcessorClient": {
"EventHubName": "MyHub",
"ClientOptions": {
"Identifier": "PROCESSOR_ID"
}
}
}
}
}
}
}
Você também pode configurar o tipo Opções usando o parâmetro Action<IAzureClientBuilder<EventProcessorClient, EventProcessorClientOptions>> configureClientBuilder
opcional do método AddAzureEventProcessorClient
. Por exemplo, para definir a ID do cliente do processador para este cliente:
builder.AddAzureEventProcessorClient(
"event-hubs",
configureClientBuilder: clientBuilder => clientBuilder.ConfigureOptions(
options => options.Identifier = "PROCESSOR_ID"));
Observabilidade e telemetria
.NET .NET Aspire integrações configuram automaticamente configurações de Log, Rastreamento e Métricas, que às vezes são conhecidas como os pilares da observabilidade. Para obter mais informações sobre a observabilidade e a telemetria de integração, consulte .NET.NET Aspire visão geral das integrações. Dependendo do serviço de backup, algumas integrações só podem dar suporte a alguns desses recursos. Por exemplo, algumas integrações dão suporte a registro em log e rastreamento, mas não a métricas. Os recursos de telemetria também podem ser desabilitados usando as técnicas apresentadas na seção Configuration.
Registro de Eventos
A integração .NET AspireAzure Event Hubs usa as seguintes categorias de log:
Azure.Core
Azure.Identity
Rastreamento
A integração .NET AspireAzure Event Hubs emitirá as seguintes atividades de rastreamento usando OpenTelemetry:
Azure.Messaging.EventHubs.*
Métricas
A integração .NET AspireAzure Event Hubs atualmente não dá suporte a métricas por padrão devido a limitações com o SDK Azure para .NET. Se isso mudar no futuro, esta seção será atualizada para refletir essas alterações.
Consulte também
- Azure Event Hubs
- visão geral das integrações .NET AspireAzure
- .NET .NET Aspire integrações
- .NET Aspire GitHub repositório