Armazenar dados em bancos de dados em conformidade com SQL

Concluído

A pilha do .NET Aspire foi criada para aumentar sua produtividade e ajudar no desenvolvimento de aplicativos web robustos, escalonáveis e seguros. Você pode armazenar dados relacionais estruturados rapidamente adicionando uma das integrações do Aspire com suporte.

As integrações atuais do banco de dados compatível com SQL são:

  • Bancos de dados PostgreSQL
  • Bancos de dados SQL
  • Bancos de Dados Oracle
  • Bancos de dados MySQL

Observação

A Microsoft pode adicionar suporte para outros sistemas de banco de dados e terceiros também podem contribuir, portanto, essa lista pode se expandir.

Nesta unidade, saiba mais sobre três dessas integrações, quais bancos de dados têm suporte do Entity Framework Core e como usá-las para armazenar e recuperar dados.

Como adicionar uma integração de banco de dados ao seu projeto

Seja qual for o banco de dados escolhido, a abordagem para adicionar uma integração de banco de dados do .NET Aspire ao seu projeto é a mesma.

No projeto de host do aplicativo:

  • Instale a integração de hospedagem do .NET Aspire no projeto de hospedagem do aplicativo.
  • Registre um banco de dados e crie um contêiner para ele no host do aplicativo da solução.
  • Passe uma referência para os projetos que precisam de acesso ao contêiner criado que hospeda o banco de dados.

Nos projetos que usam o banco de dados:

  • Adicione a integração do .NET Aspire com um pacote NuGet aos projetos que exigem acesso a dados. Opcionalmente, se existir uma integração do .NET Core Entity Framework (EF) , você poderá usá-la.
  • Registre a fonte de dados ou o contexto do banco de dados para EF no arquivo de Program.cs do projeto.
  • Use a injeção de dependência para injetar a fonte de dados em seus serviços.

Vamos examinar as especificidades de como executar essas etapas para cada um dos bancos de dados com suporte.

Usando as integrações do PostgreSQL do .NET Aspire

As integrações do .NET Aspire PostgreSQL exigem alterações no projeto de host do aplicativo e nos microsserviços que usam os bancos de dados.

Configurar o host de aplicativo

Comece instalando a integração de hospedagem apropriada ao host do aplicativo:

dotnet add package Aspire.Hosting.PostgreSQL --prerelease

Em seguida, para registrar um banco de dados e criar um contêiner para ele, adicione este código ao arquivo Program.cs do host do aplicativo:

var postgres = builder.AddPostgres("postgres");
var postgresdb = postgres.AddDatabase("postgresdb");

Você também deve passar uma referência ao serviço de banco de dados para todos os projetos que o consomem:

var northernTradersCatalogAPI = builder.AddProject<Projects.NorthernTraders_CatalogAPI>()
                                       .WithReference(postgresdb);

Como configurar os projetos de consumo

Para instalar a integração do .NET Aspire PostgreSQL, use um comando como este em seus projetos do .NET Aspire:

dotnet add package Aspire.Npgsql --prerelease

Ou para usar a integração do .NET Aspire PostgreSQL Entity Framework Core, use este comando em vez disso:

dotnet add package Aspire.Npgsql.EntityFrameworkCore.PostgreSQL --prerelease

Como alternativa, você pode usar o atalho adicionar > pacote do .NET Aspire no Visual Studio para instalar a integração do gerenciador de pacotes NuGet:

Captura de tela mostrando o gerenciador de pacotes NuGet no Visual Studio exibindo integrações postgreSQL do .NET Aspire.

Código no arquivo *.AppHost do projeto Program.cs cria o banco de dados e o transfere para projetos que desejam usá-lo:

var postgres = builder.AddPostgres("pg")
                      .AddDatabase("postgresdb");

var exampleProject = builder.AddProject<Projects.SampleProject>()
                            .WithReference(postgres);

Algumas das integrações de banco de dados do .NET Aspire também permitem que você crie um contêiner para ferramentas de gerenciamento de banco de dados. Para adicionar PgAdmin à sua solução para gerenciar o banco de dados PostgreSQL, use este código:

var postgresdb = builder.AddPostgres("pg")
                        .AddDatabase("postgresdb")
                        .WithPgAdmin();

A vantagem de permitir que o .NET Aspire crie o contêiner é que você não precisa fazer nenhuma configuração para conectar o PgAdmin ao banco de dados PostgreSQL, é tudo automático.

Usando um banco de dados PostgreSQL

Em qualquer projeto em que você queira usar o banco de dados, adicione uma fonte de dados para representar a conexão com o PostgreSQL. No arquivo Program.cs , esse código registra o banco de dados:

builder.AddNpgsqlDataSource("postgresdb");

Ou para usar a integração do Entity Framework Core, registre o contexto do banco de dados:

builder.AddNpgsqlDbContext<YourDbContext>("postgresdb");

Depois que o banco de dados estiver registrado no projeto de consumo, você poderá interagir com a fonte de dados sempre que precisar usando a injeção de dependência:

public class YourService(NpgsqlDataSource dataSource)
{
    public async Task<IEnumerable<Catalog>> GetCatalog()
	{
        const string query = "SELECT * FROM catalog";
        using var dbConnection = dataSource.OpenConnection();
        var results = await dbConnection.QueryAsync<Catalog>(command);
        return queryResult.ToArray();
	}
}

Ou então você pode recuperar o contexto YourDbContext do banco de dados para interagir com o banco de dados:

public class YourService(YourDbContext context)
{
    public async Task<IEnumerable<Catalog>> GetCatalog()
	{
        var items = await context.ObjectItems;
        if (item is null)
        {
            return Results.NotFound();
        }
		else
		{
		    return items;
		}
	}
}

Configurando a integração do PostgreSQL

A pilha do .NET Aspire tenta reduzir a quantidade de configurações que você precisa fazer. Usando a injeção de dependência e a descoberta de serviço, você pode acessar o banco de dados sem precisar configurar as cadeias de conexão em seus projetos.

Usar o projeto de host do aplicativo para criar o contêiner de banco de dados e passá-lo como referência aos projetos permite que os projetos receptores acessem o local do banco de dados, as cadeias de conexão e as portas. Não é necessário gerenciar variáveis de ambiente ou arquivosappsettings.json .

Mas, se desejar ou precisar de mais controle sobre como o banco de dados está configurado, há mais opções.

Usando uma cadeia de conexão

No projeto que requer o banco de dados, você usa uma cadeia de conexão para se conectar ao banco de dados. Essa abordagem é útil quando você precisa se conectar a um banco de dados que não está registrado no host do aplicativo.

builder.AddNpgsqlDataSource("NpgsqlConnectionString");

Em seguida, no arquivo de configuração, você pode adicionar a cadeia de conexão:

{
  "ConnectionStrings": {
    "NpgsqlConnectionString": "Host=myserver;Database=postgresdb;User id=myuser;Password=mypassword"
  }
}

Usando provedores de configuração

O .NET Aspire tem um recurso de integrações que lhes permite oferecer suporte a Microsoft.Extensions.Configuration. A integração do PostgreSQL dá suporte a esse recurso e, por padrão, procura configurações usando a Aspire:Npgsql chave. Em projetos que usam appsettings.json, uma configuração de exemplo pode ter esta aparência:

{
  "Aspire": {
    "Npgsql": {
      "ConnectionString": "Host=myserver;Database=postgresdb;User id=myuser;Password=mypassword",
      "HealthChecks": true,
      "Tracing": true,
      "Metrics": true
    }
  }
}

A configuração anterior é definir a cadeia de conexão, habilitando verificações de integridade, rastreamento e métricas para a integração do PostgreSQL. Em seguida, você não precisa mais especificar a cadeia de conexão, basta usar builder.AddNpgsqlDataSource();.

Se você estiver usando a integração do PostgreSQL Entity Framework Core, poderá usar a Aspire:Npgsql:EntityFrameworkCore:PostgreSQL chave para configurar o contexto do banco de dados:

{
  "Aspire": {
    "Npgsql": {
      "EntityFrameworkCore": {
        "PostgreSQL": {
          "ConnectionString": "Host=myserver;Database=postgresdb;User id=myuser;Password=mypassword",
          "MaxRetryCount": 0,
          "HealthChecks": false,
          "Tracing": false
        }
      }
    }
  }
}

Para obter mais informações sobre as opções de configuração do Entity Framework, consulte a documentação do .NET Aspire.

Usar delegados embutidos

A última opção é passar um delegado embutido configureSettings para o método AddNpgsqlDataSource. Esse delegado permite que você defina as configurações para a integração do banco de dados diretamente com o código:

builder.AddNpgsqlDataSource(
    "postgresdb", static settings => settings.HealthChecks = false);

Usando as integrações do Banco de Dados SQL do .NET Aspire

O padrão anterior é o mesmo para a integração do Banco de Dados SQL. Você faz alterações no projeto de host do aplicativo e nos microsserviços que consomem o serviço de banco de dados.

Configurar o host de aplicativo

Para instalar a integração de hospedagem do banco de dados SQL, use este comando:

dotnet add package Aspire.Hosting.SqlServer --prerelease

Para registrar o contêiner e o banco de dados, adicione este código ao arquivo de Program.cs do host do aplicativo:

var sql = builder.AddSqlServer("sql");
var sqldb = sql.AddDatabase("sqldb");

Em seguida, passe uma referência ao serviço de banco de dados para todos os projetos que o consomem:

var northernTradersCatalogAPI = builder.AddProject<Projects.NorthernTraders_CatalogAPI>()
                                       .WithReference(sqldb);

Como configurar os projetos de consumo

Para instalar a integração do Banco de Dados SQL do .NET Aspire, use um comando como este em seus projetos do .NET Aspire:

dotnet add package Aspire.Microsoft.Data.SqlClient --prerelease

Ou para usar a integração do .NET Aspire SqlServer Entity Framework Core, use este comando em vez disso:

dotnet add package Aspire.Microsoft.EntityFrameworkCore.SqlServer --prerelease

Esses pacotes NuGet também podem ser adicionados usando o atalho adicionar > pacote do .NET Aspire no Visual Studio.

O código do arquivo Program.cs do projeto *.AppHost para acessar o banco de dados é semelhante ao exemplo do PostgreSQL:

var sqlServer = builder.AddSqlServer("sql")
                       .AddDatabase("sqldata");

var myService = builder.AddProject<Projects.MyService>()
                       .WithReference(sqlServer);

Usando um banco de dados do SQL Server

Nos projetos que precisam de acesso ao SQL, no arquivo Program.cs , esse código registra o contexto do banco de dados do Entity Framework:

builder.AddSqlServerDbContext<YourDbContext>("sqldata");

Depois que o banco de dados for registrado no projeto de consumo, você poderá interagir com o contexto YourDbContext do banco de dados usando a injeção de dependência. Este código de exemplo recupera previsões meteorológicas de um banco de dados e seleciona uma aleatoriamente para retornar:

app.MapGet("/weatherforecast", async (YourDbContext context) =>
{
  var rng = new Random();
  var forecasts = await context.Forecasts.ToListAsync();
  var forecast = forecasts[rng.Next(forecasts.Count)];
  return forecast;
});

Configurando a integração do SQL Server

Como antes, se você usar o mesmo nome de banco de dados no host do aplicativo e no projeto de consumo, não precisará configurar a conexão entre o banco de dados do SQL Server e os projetos. A integração do .NET Aspire SQL Server também dá suporte a outras maneiras de configurar a integração.

Usando provedores de configuração

A integração do SQL Server também suporta Microsoft.Extensions.Configuration. Por padrão, ele procura configurações usando a Aspire:SqlServer:SqlClient chave. Em projetos que usam appsettings.json, uma configuração de exemplo pode ter esta aparência:

{
  "Aspire": {
    "SqlServer": {
      "SqlClient": {
        "ConnectionString": "YOUR_CONNECTIONSTRING",
        "HealthChecks": true,
        "Tracing": false,
        "Metrics": false
      }
    }
  }
}

Como usar configurações embutidas

Ao adicionar a integração do SQL Server, você pode passar um delegado embutido configureSettings para o método AddSqlServerClient. Esse delegado permite que você defina as configurações para a integração do banco de dados diretamente com o código:

builder.AddSqlServerClient("sqldata", static settings => settings.HealthChecks = false);

Você pode fornecer qualquer uma das opções com suporte:

  • ConnectionString: a cadeia de conexão do banco de dados do SQL Server
  • HealthChecks: um valor booliano que indica se a verificação de integridade do banco de dados está habilitada
  • Tracing: um valor booliano que indica se o rastreamento OpenTelemetry está habilitado
  • Metrics: um valor booliano que indica se as métricas OpenTelemetry estão habilitadas

Conectar-se a vários bancos de dados

A integração do SQL Server dá suporte a várias conexões por meio de instâncias nomeadas. Por exemplo, você pode se conectar a dois bancos de dados diferentes do SQL Server no mesmo projeto:

{
  "Aspire": {
    "SqlServer": {
      "SqlClient": {
        "INSTANCE_1": {
          "ServiceUri": "YOUR_URI",
          "HealthChecks": false
        },
        "INSTANCE_2": {
          "ServiceUri": "YOUR_URI",
          "HealthChecks": false
        }
      }
    }
  }
}

Usando essa configuração, você pode se conectar aos dois bancos de dados diferentes no mesmo projeto:

builder.AddSqlServerClient("INSTANCE_1");
builder.AddSqlServerClient("INSTANCE_2");

Usando a integração do MySQL

Para instalar a integração mySQL do .NET Aspire, use um comando como este em seus projetos do .NET Aspire que exigem acesso a dados:

dotnet add package Aspire.MySqlConnector --prerelease

Ou use o atalho adicionar > pacote do .NET Aspire no Visual Studio para instalar a integração do gerenciador de pacotes NuGet.

O código do arquivo Program.cs do projeto *.AppHost para acessar o banco de dados é semelhante ao exemplo do PostgreSQL:

var mysqldb = builder.AddMySql("mysql")
                     .AddDatabase("mysqldb")
                     .WithPhpMyAdmin();

var myService = builder.AddProject<Projects.MyService>()
                       .WithReference(mysqldb);

Assim como a integração do PostgreSQL, a integração do MySQL também permite que você crie um contêiner para ferramentas de gerenciamento de banco de dados. O exemplo anterior adiciona PhpMyAdmin à solução.

Usando um banco de dados MySQL

O padrão é o mesmo nos projetos que precisam de acesso ao MySQL. No arquivo Program.cs , esse código registra o banco de dados:

builder.AddMySqlDataSource("mysqldb");

Depois que o banco de dados estiver registrado no projeto de consumo, você poderá interagir com a fonte de dados sempre que precisar usando a injeção de dependência:

app.MapGet("/catalog", async (MySqlConnection db) =>
{
    const string sql = """
        SELECT Id, Name, Description, Price
        FROM catalog
        """;

    // the db object is a connection to the MySQL database registered with AddMySqlDataSource
    return await db.QueryAsync<CatalogItem>(sql);
});

Configurando a integração do MySQL

A integração do MySQL dá suporte às mesmas três opções para gerenciar a configuração.

Cadeias de conexão

O arquivo appsettings.json pode conter a cadeia de conexão do banco de dados MySQL:

{
  "ConnectionStrings": {
    "MySqConnection": "Server=myserver;Database=mysqldb;Uid=myuser;Pwd=mypassword"
  }
}

Em seguida, em seu projeto, você pode se conectar ao banco de dados com a cadeia de conexão usando um código como este:

builder.AddMySqlDataSource("MySqConnection");

Provedores de configuração

A Aspire:MySqlConnector chave é usada para configurar a integração do MySQL.

{
  "Aspire": {
    "MySqlConnector": {
      "ConnectionString": "Server=myserver;Database=mysqldb;Uid=myuser;Pwd=mypassword",
      "HealthChecks": true,
      "Tracing": false,
      "Metrics": false
    }
  }
}

Configurações embutidas

builder.AddMySqlDataSource("mysqldb", static settings => settings.HealthChecks = false);

Saiba como propagar seu banco de dados

A tecnologia .NET Aspire utiliza contêineres, aproveitando as vantagens de ambientes consistentes e implantações simplificadas. Uma desvantagem é que os contêineres ficarão sem estado. Todos os dados ou esquemas adicionados a um banco de dados são perdidos quando o contêiner é destruído. O .NET Aspire fornece maneiras de preencher seus bancos de dados com informações ao criar seus contêineres.

Como usar volumes e scripts

A maneira mais simples de propagar seu banco de dados é usar volumes e scripts SQL. Os volumes podem armazenar dados para vários contêineres de cada vez, oferecer alto desempenho e são fáceis de fazer backup ou migrar. Os scripts armazenados nesses volumes são executados quando um contêiner é criado, preenchendo o banco de dados com dados. O script pode ser um arquivo SQL que contém os dados e o esquema desejados para o banco de dados.

Por exemplo, se você tiver esse script SQL, armazenado em um arquivo chamado postgres-backup.sql, na pasta Service.API/Seed :

CREATE TABLE catalog (
  Id INT PRIMARY KEY,
  Name VARCHAR(50),
  Description VARCHAR(255),
  Price DECIMAL(18, 2)
);

INSERT INTO catalog (Id, Name, Description, Price)
VALUES (1, 'Item 1', 'Description of item 1', 10.99),
      (2, 'Item 2', 'Description of item 2', 20.99),
      (3, 'Item 3', 'Description of item 3', 30.99);

No host do aplicativo da solução, você pode associar a pasta Service.API/Seed à pasta /docker-entrypoint-initdb.d do contêiner. Essa pasta é uma pasta especial no contêiner PostgreSQL que executa todos os scripts SQL encontrados quando o contêiner é criado:

    var catalogDB = builder.AddPostgres("postgres")
      .WithPgAdmin()
      .WithEnvironment("POSTGRES_DB", "backendDB")
      .WithBindMount("../Service.API/Seed", "/docker-entrypoint-initdb.d")
      .AddDatabase("backendDB");

Você pode até mesmo dividir os scripts SQL em scripts de criação de esquema e propagação de dados. Se estiverem todos contidos na pasta Service.API/Seed , eles serão executados quando o .NET Aspire criar o banco de dados.

Propagação de dados usando o Entity Framework Core

Para as integrações que dão suporte ao Entity Framework Core, você pode propagar seu banco de dados usando a classe DbContext e as migrações do Entity Framework Core. Esse método usa o código C# para preencher o banco de dados. Contudo, essa propagação deve ocorrer somente durante o desenvolvimento ou testes, e não em produção.

// Register DbContext class
builder.AddNpgsqlDbContext<CatalogContext>("sqldata");

var app = builder.Build();

app.MapDefaultEndpoints();

if (app.Environment.IsDevelopment())
{
    // Retrieve an instance of the DbContext class and manually run migrations during development
    using (var scope = app.Services.CreateScope())
    {
        var context = scope.ServiceProvider.GetRequiredService<CatalogContext>();
        context.Database.EnsureCreated();
    }
}

O código acima verifica o estado do ambiente do aplicativo. Se estiver em desenvolvimento, o código recuperará a CatalogContext classe e executará o EnsureCreated método. Esse método cria o banco de dados e executa todas as migrações pendentes.

Para obter mais informações sobre como propagar as diferentes integrações de banco de dados, consulte a documentação do .NET Aspire.