Compartilhar via


Início Rápido: crie seu primeiro aplicativo Orleans com o ASP.NET Core

Neste início rápido, você usará Orleans e as APIs mínimas do ASP.NET Core 8.0 para criar um aplicativo encurtador de URL. Os usuários enviam uma URL completa para o ponto de extremidade /shorten do aplicativo e obtêm uma versão abreviada para compartilhar com outras pessoas, que são redirecionadas para o site original. O aplicativo usa Orleans grãos e silos para gerenciar o estado de forma distribuída, permitindo escalabilidade e resiliência. Esses recursos são essenciais ao desenvolver aplicativos para serviços de hospedagem em nuvem distribuída, como Aplicativos de Contêiner do Azure e plataformas como Kubernetes.

No final do início rápido, você tem um aplicativo que cria e manipula redirecionamentos usando URLs curtas e amigáveis. Você aprenderá como:

  • Adicionar Orleans a um aplicativo ASP.NET Core
  • Trabalhar com grãos e silos
  • Configurar o gerenciamento de estado
  • Integrar o Orleans com pontos de extremidade de API

Pré-requisitos

Criar o aplicativo

  1. Inicie o Visual Studio 2022 e selecione Criar um novo projeto.

  2. Na caixa de diálogo Criar um novo projeto, selecione API de Aplicativo Web ASP.NET Core e, em seguida, selecione Avançar.

  3. Na caixa de diálogo Configurar novo projeto, digite OrleansURLShortener como Nome do projeto e selecione em Avançar.

  4. Na caixa de diálogo Informações adicionais, selecione .NET 8.0 (Suporte de Longo Prazo) e desmarque Usar controladores e, em seguida, selecione Criar.

Adicionar Orleans ao projeto

O Orleans está disponível por meio de uma coleção de pacotes NuGet e cada um deles fornece acesso a vários recursos. Neste início rápido, adicione o pacote NuGet Microsoft.Orleans.Server ao aplicativo:

  • Clique com o botão direito do mouse no nó do projeto OrleansURLShortener no gerenciador de soluções e selecione Gerenciar Pacotes NuGet.
  • Na janela do gerenciador de pacotes, pesquise Orleans.
  • Escolha o pacote Microsoft.Orleans.Server nos resultados da pesquisa e selecione Instalar.

Abra o arquivo Program.cs e substitua o conteúdo existente pelo seguinte código:

using Orleans.Runtime;

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();

Configurar os silos

Os silos são um bloco de construção principal do Orleans responsável por armazenar e gerenciar grãos. Um silo pode conter um ou mais grãos; um grupo de silos é conhecido como um aglomerado. As coordenadas do cluster funcionam entre silos, permitindo a comunicação com grãos como se todos estivessem disponíveis em um único processo.

Na parte superior do arquivo Program.cs, refatore o código para usar o Orleans. O código a seguir usa uma classe ISiloBuilder para criar um cluster localhost com um silo que pode armazenar grãos. O ISiloBuilder também usa o AddMemoryGrainStorage para configurar os silos do Orleans a fim de manter granularidades na memória. Este cenário usa recursos locais para desenvolvimento, mas um aplicativo de produção pode ser configurado para usar clusters e armazenamento altamente escalonáveis usando serviços como o Armazenamento de Blob do Azure.

using Orleans.Runtime;

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseOrleans(static siloBuilder =>
{
    siloBuilder.UseLocalhostClustering();
    siloBuilder.AddMemoryGrainStorage("urls");
});

using var app = builder.Build();

Criar o encurtador de URL chamado Grain

Granularidades são os blocos de construção e primitivos mais essenciais de aplicativos do Orleans. Um grain é uma classe que herda da classe base Grain, que gerencia vários comportamentos internos e pontos de integração com Orleans. As granularidades também devem implementar uma das interfaces listadas abaixo para definir o tipo de identificador da chave de granularidade. Cada uma dessas interfaces define um contrato semelhante, mas marca sua classe com um tipo de dados diferente para o identificador que o Orleans usa para rastrear a granularidade, como uma cadeia de caracteres ou inteiro.

Neste início rápido, você usará o IGrainWithStringKey, pois as cadeias de caracteres são uma opção lógica para trabalhar com valores de URL e códigos curtos.

As granularidades do Orleans também podem usar uma interface personalizada para definir seus métodos e propriedades. A interface de granulador de URL deve definir dois métodos:

  • Um método SetUrl para persistir as URLs originais e suas URLs abreviadas correspondentes.
  • Um método GetUrl para recuperar a URL original usando a URL abreviada.
  1. Anexe a seguinte definição de interface à parte inferior do arquivo Program.cs.

    public interface IUrlShortenerGrain : IGrainWithStringKey
    {
        Task SetUrl(string fullUrl);
    
        Task<string> GetUrl();
    }
    
  2. Crie uma classe UrlShortenerGrain usando o código a seguir. Essa classe herda da classe Grain fornecida por Orleans e implementa a interface IUrlShortenerGrain que você criou. A classe também usa a interface IPersistentState do Orleans para gerenciar a leitura e a gravação de valores de estado para as URLs no silo de armazenamento configurado.

    public sealed class UrlShortenerGrain(
        [PersistentState(
            stateName: "url",
            storageName: "urls")]
            IPersistentState<UrlDetails> state)
        : Grain, IUrlShortenerGrain
    {
        public async Task SetUrl(string fullUrl)
        {
            state.State = new()
            {
                ShortenedRouteSegment = this.GetPrimaryKeyString(),
                FullUrl = fullUrl
            };
    
            await state.WriteStateAsync();
        }
    
        public Task<string> GetUrl() =>
            Task.FromResult(state.State.FullUrl);
    }
    
    [GenerateSerializer, Alias(nameof(UrlDetails))]
    public sealed record class UrlDetails
    {
        [Id(0)]
        public string FullUrl { get; set; } = "";
    
        [Id(1)]
        public string ShortenedRouteSegment { get; set; } = "";
    }
    

Criar os pontos de extremidade

Em seguida, crie dois pontos de extremidade para utilizar as configurações de granularidade e silo do Orleans:

  • Um ponto de extremidade /shorten para lidar com a criação e o armazenamento de uma versão abreviada da URL. A URL original completa é fornecida como um parâmetro de cadeia de caracteres de consulta chamado urle a URL abreviada é retornada ao usuário para uso posterior.
  • Um endpoint /go/{shortenedRouteSegment:required} para lidar com o redirecionamento de usuários para a URL original usando a URL encurtada fornecida como parâmetro.

Injete a interface IGrainFactory em ambos os pontos de extremidade. As Fábricas de Grãos permitem que você recupere e gerencie referências a grãos individuais armazenados em silos. Anexe o seguinte código ao arquivo Program.cs antes da chamada do método app.Run():

app.MapGet("/", static () => "Welcome to the URL shortener, powered by Orleans!");

app.MapGet("/shorten",
    static async (IGrainFactory grains, HttpRequest request, string url) =>
    {
        var host = $"{request.Scheme}://{request.Host.Value}";

        // Validate the URL query string.
        if (string.IsNullOrWhiteSpace(url) ||
            Uri.IsWellFormedUriString(url, UriKind.Absolute) is false)
        {
            return Results.BadRequest($"""
                The URL query string is required and needs to be well formed.
                Consider, ${host}/shorten?url=https://www.microsoft.com.
                """);
        }

        // Create a unique, short ID
        var shortenedRouteSegment = Guid.NewGuid().GetHashCode().ToString("X");

        // Create and persist a grain with the shortened ID and full URL
        var shortenerGrain =
            grains.GetGrain<IUrlShortenerGrain>(shortenedRouteSegment);

        await shortenerGrain.SetUrl(url);

        // Return the shortened URL for later use
        var resultBuilder = new UriBuilder(host)
        {
            Path = $"/go/{shortenedRouteSegment}"
        };

        return Results.Ok(resultBuilder.Uri);
    });

app.MapGet("/go/{shortenedRouteSegment:required}",
    static async (IGrainFactory grains, string shortenedRouteSegment) =>
    {
        // Retrieve the grain using the shortened ID and url to the original URL
        var shortenerGrain =
            grains.GetGrain<IUrlShortenerGrain>(shortenedRouteSegment);

        var url = await shortenerGrain.GetUrl();

        // Handles missing schemes, defaults to "http://".
        var redirectBuilder = new UriBuilder(url);

        return Results.Redirect(redirectBuilder.Uri.ToString());
    });

app.Run();

Teste o aplicativo finalizado

A funcionalidade principal do aplicativo agora está completa e pronta para ser testada. O código final do aplicativo deve corresponder ao seguinte exemplo:

// <configuration>
using Orleans.Runtime;

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseOrleans(static siloBuilder =>
{
    siloBuilder.UseLocalhostClustering();
    siloBuilder.AddMemoryGrainStorage("urls");
});

using var app = builder.Build();
// </configuration>

// <endpoints>
app.MapGet("/", static () => "Welcome to the URL shortener, powered by Orleans!");

app.MapGet("/shorten",
    static async (IGrainFactory grains, HttpRequest request, string url) =>
    {
        var host = $"{request.Scheme}://{request.Host.Value}";

        // Validate the URL query string.
        if (string.IsNullOrWhiteSpace(url) ||
            Uri.IsWellFormedUriString(url, UriKind.Absolute) is false)
        {
            return Results.BadRequest($"""
                The URL query string is required and needs to be well formed.
                Consider, ${host}/shorten?url=https://www.microsoft.com.
                """);
        }

        // Create a unique, short ID
        var shortenedRouteSegment = Guid.NewGuid().GetHashCode().ToString("X");

        // Create and persist a grain with the shortened ID and full URL
        var shortenerGrain =
            grains.GetGrain<IUrlShortenerGrain>(shortenedRouteSegment);

        await shortenerGrain.SetUrl(url);

        // Return the shortened URL for later use
        var resultBuilder = new UriBuilder(host)
        {
            Path = $"/go/{shortenedRouteSegment}"
        };

        return Results.Ok(resultBuilder.Uri);
    });

app.MapGet("/go/{shortenedRouteSegment:required}",
    static async (IGrainFactory grains, string shortenedRouteSegment) =>
    {
        // Retrieve the grain using the shortened ID and url to the original URL
        var shortenerGrain =
            grains.GetGrain<IUrlShortenerGrain>(shortenedRouteSegment);

        var url = await shortenerGrain.GetUrl();

        // Handles missing schemes, defaults to "http://".
        var redirectBuilder = new UriBuilder(url);

        return Results.Redirect(redirectBuilder.Uri.ToString());
    });

app.Run();
// </endpoints>

// <graininterface>
public interface IUrlShortenerGrain : IGrainWithStringKey
{
    Task SetUrl(string fullUrl);

    Task<string> GetUrl();
}
// </graininterface>

// <grain>
public sealed class UrlShortenerGrain(
    [PersistentState(
        stateName: "url",
        storageName: "urls")]
        IPersistentState<UrlDetails> state)
    : Grain, IUrlShortenerGrain
{
    public async Task SetUrl(string fullUrl)
    {
        state.State = new()
        {
            ShortenedRouteSegment = this.GetPrimaryKeyString(),
            FullUrl = fullUrl
        };

        await state.WriteStateAsync();
    }

    public Task<string> GetUrl() =>
        Task.FromResult(state.State.FullUrl);
}

[GenerateSerializer, Alias(nameof(UrlDetails))]
public sealed record class UrlDetails
{
    [Id(0)]
    public string FullUrl { get; set; } = "";

    [Id(1)]
    public string ShortenedRouteSegment { get; set; } = "";
}
// </grain>

Teste o aplicativo no navegador usando as seguintes etapas:

  1. Inicie o aplicativo usando o botão executar na parte superior do Visual Studio. O aplicativo deve ser iniciado no navegador e exibir o texto familiar Hello world!.

  2. Na barra de endereços do navegador, teste o endpoint shorten inserindo um caminho de URL, como {localhost}/shorten?url=https://learn.microsoft.com. A página deve recarregar e fornecer uma URL abreviada. Copie a URL abreviada para sua área de transferência.

    Uma captura de tela mostrando o resultado do encurtador de URL iniciado no Visual Studio.

  3. Cole a URL abreviada na barra de endereços e pressione Enter. A página deve recarregar e redirecionar você para https://learn.microsoft.com.