Archiviare i dati nei database conformi a SQL

Completato

Lo stack .NET Aspire è progettato per aumentare la produttività e per facilitare la creazione di applicazioni Web affidabili, scalabili e sicure. È possibile archiviare rapidamente dati relazionali strutturati aggiungendo uno dei componenti Aspire supportati.

I componenti di database conformi a SQL correnti sono:

  • Database PostgreSQL
  • Database SQL
  • Database Oracle
  • Database MySQL

Nota

Microsoft può aggiungere supporto per altri sistemi di database e possono contribuire anche terze parti, quindi questo elenco può espandersi.

In questa unità vengono fornite informazioni su tre di questi componenti, sui database con supporto di Entity Framework Core e su come usarli per archiviare e recuperare i dati.

Come aggiungere un componente di database al progetto

Indipendentemente dal database scelto, l'approccio per aggiungere un componente di database .NET Aspire al progetto è lo stesso.

Nel progetto host dell'app:

  • Installare il componente di hosting .NET Aspire nel progetto host dell'app.
  • Registrare un database e crearne uno nell'host dell'app della soluzione.
  • Passare un riferimento ai progetti che devono accedere al contenitore creato che ospita il database.

Nei progetti che usano il database:

  • Aggiungere il componente .NET Aspire con un pacchetto NuGet ai progetti che richiedono l'accesso ai dati. Facoltativamente, se è presente un componente .NET Core Entity Framework (EF), è possibile usarlo.
  • Registrare l'origine dati o il contesto del database per Entity Framework nel file di Program.cs del progetto.
  • Usare l'inserimento delle dipendenze per inserire l'origine dati nei servizi.

Verranno ora esaminate le specifiche di come eseguire questi passaggi per ognuno dei database supportati.

Uso dei componenti PostgreSQL di .NET Aspire

I componenti PostgreSQL .NET Aspire richiedono modifiche sia nel progetto host dell'app che nei microservizi che usano i database.

Configurazione dell'host dell'app

Per iniziare, installare il componente di hosting appropriato nell'host dell'app:

dotnet add package Aspire.Hosting.PostgreSQL --prerelease

Successivamente, per registrare un database e crearne uno, aggiungere questo codice al file di Program.cs dell'host dell'app:

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

È inoltre necessario passare un riferimento al servizio di database a tutti i progetti che lo utilizzano:

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

Configurare i progetti che utilizzano la cache

Per installare il componente PostgreSQL .NET Aspire, usare un comando simile al seguente nei progetti .NET Aspire:

dotnet add package Aspire.Npgsql --prerelease

In alternativa, per usare il componente .NET Aspire PostgreSQL Entity Framework Core, usare questo comando:

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

In alternativa, è possibile usare il collegamento Aggiungi > Componente .NET Aspire in Visual Studio per installare il componente dalla gestione pacchetti di NuGet:

Screenshot che mostra la gestione pacchetti NuGet in Visual Studio che mostra i componenti PostgreSQL di .NET Aspire.

Codice nel file Program.cs del progetto *. AppHost crea il database e lo passa ai progetti che vogliono usarlo:

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

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

Alcuni dei componenti di database .NET Aspire consentono anche di creare un contenitore per gli strumenti di gestione del database. Per aggiungere PgAdmin alla soluzione per gestire il database PostgreSQL, usare questo codice:

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

Il vantaggio di consentire a .NET Aspire di creare il contenitore è che non è necessario eseguire alcuna configurazione per connettere PgAdmin al database PostgreSQL, è tutto automatico.

Uso di un database PostgreSQL

In qualsiasi progetto in cui si vuole usare il database, si aggiunge un'origine dati per rappresentare la connessione a PostgreSQL. Nel file Program.cs questo codice registra il database:

builder.AddNpgsqlDataSource("postgresdb");

In alternativa, per usare il componente Entity Framework Core, registrare il contesto del database:

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

Dopo aver registrato il database nel progetto di utilizzo, è possibile interagire con l'origine dati ogni volta che è necessario usando l'inserimento delle dipendenze:

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();
	}
}

In alternativa, è possibile recuperare il contesto YourDbContext del database per interagire con il database:

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;
		}
	}
}

Configurazione del componente PostgreSQL

Lo stack .NET Aspire tenta di ridurre la quantità di configurazione che è necessario eseguire. Usando l'inserimento delle dipendenze e l'individuazione del servizio, è possibile accedere al database senza dover configurare le stringhe di connessione nei progetti.

L'uso del progetto host dell'app per creare il contenitore di database e passarlo come riferimento ai progetti consente ai progetti riceventi di accedere al percorso del database, alle stringhe di connessione e alle porte. Non è necessario gestire variabili di ambiente o file appsettings.json.

Tuttavia, se si vuole o è necessario un maggiore controllo sul modo in cui è configurato il database, sono disponibili altre opzioni.

Uso di una stringa di connessione

Nel progetto che richiede il database usare una stringa di connessione per connettersi al database. Questo approccio è utile quando è necessario connettersi a un database non registrato nell'host dell'app.

builder.AddNpgsqlDataSource("NpgsqlConnectionString");

Nel file di configurazione è quindi possibile aggiungere la stringa di connessione:

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

Uso dei provider di configurazione

.NET Aspire ha una funzionalità di componenti che consente loro di supportare un oggetto Microsoft.Extensions.Configuration. Il componente PostgreSQL supporta questa funzionalità e per impostazione predefinita cerca le impostazioni usando la chiave Aspire:Npgsql. Nei progetti che usano appsettings.json, una configurazione di esempio potrebbe essere simile alla seguente:

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

La configurazione precedente imposta la stringa di connessione, abilitando controlli di integrità, traccia e metriche per il componente PostgreSQL. Il codice non deve più specificare la stringa di connessione, ma usare solo builder.AddNpgsqlDataSource();.

Se si usa il componente PostgreSQL Entity Framework Core, è possibile usare la chiave Aspire:Npgsql:EntityFrameworkCore:PostgreSQL per configurare il contesto del database:

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

Per altre informazioni sulle opzioni di configurazione di Entity Framework, vedere la documentazione di .NET Aspire.

Uso di delegati inline

L'ultima opzione consiste nel passare un delegato inline configureSettings al metodo AddNpgsqlDataSource. Questo delegato consente di configurare le impostazioni per il componente di database direttamente con il codice:

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

Uso dei componenti del database SQL Aspire .NET

Il modello precedente è lo stesso per il componente del database SQL. Si apportano modifiche sia nel progetto host dell'app che nei microservizi che utilizzano il servizio di database.

Configurazione dell'host dell'app

Per installare il componente di hosting del database SQL, usare questo comando:

dotnet add package Aspire.Hosting.SqlServer --prerelease

Per registrare il contenitore e il database, aggiungere questo codice al file di Program.cs dell'host dell'app:

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

Passare quindi un riferimento al servizio di database a tutti i progetti che lo utilizzano:

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

Configurare i progetti che utilizzano la cache

Per installare il componente database SQL Aspire .NET, usare un comando simile al seguente nei progetti .NET Aspire:

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

In alternativa, per usare il componente .NET Aspire SqlServer Entity Framework Core, usare questo comando:

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

Questi pacchetti NuGet possono essere aggiunti anche usando il collegamento Aggiungi > componente .NET Aspire in Visual Studio.

Il codice del file *.Program.cs del progetto AppHost per accedere al database è simile all'esempio postgreSQL:

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

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

Uso di un database di SQL Server

Nei progetti che richiedono l'accesso a SQL, nel file Program.cs, questo codice registra il contesto del database Entity Framework:

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

Dopo aver registrato il database nel progetto di utilizzo, è possibile interagire con il contesto YourDbContext del database usando l'inserimento delle dipendenze. Questo codice di esempio recupera le previsioni meteo da un database e ne seleziona uno in modo casuale per restituire:

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;
});

Configurazione del componente SQL Server

Come in precedenza, se si usa lo stesso nome di database nell'host dell'app e nel progetto di utilizzo, non è necessario configurare la connessione tra il database di SQL Server e i progetti. Il componente .NET Aspire a SQL Server supporta anche altri modi per configurare il componente.

Uso dei provider di configurazione

Il componente SQL Server supporta anche Microsoft.Extensions.Configuration. Per impostazione predefinita, cerca le impostazioni usando la chiave Aspire:SqlServer:SqlClient. Nei progetti che usano appsettings.json, una configurazione di esempio potrebbe essere simile alla seguente:

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

Uso delle configurazioni inline

Quando si aggiunge il componente SQL Server, è possibile passare un delegato inline configureSettings al metodo AddSqlServerClient. Questo delegato consente di configurare le impostazioni per il componente di database direttamente con il codice:

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

È possibile passare una delle opzioni supportate:

  • ConnectionString: Stringa di connessione del database di SQL Server
  • HealthChecks: Valore booleano che indica se il controllo integrità del database è abilitato
  • Tracing: Valore booleano che indica se la traccia OpenTelemetry è abilitata
  • Metrics: Valore booleano che indica se le metriche OpenTelemetry sono abilitate

Connettersi a più database

Il componente SQL Server supporta più connessioni tramite istanze denominate. Ad esempio, è possibile connettersi a due database di SQL Server diversi nello stesso progetto:

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

Usando questa configurazione, è possibile connettersi ai due database diversi nello stesso progetto:

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

Uso del componente MySQL

Per installare il componente MySQL .NET Aspire, usare un comando simile al seguente nei progetti .NET Aspire che richiedono l'accesso ai dati:

dotnet add package Aspire.MySqlConnector --prerelease

Oppure è possibile usare il collegamento Aggiungi > Componente .NET Aspire in Visual Studio per installare il componente dalla gestione pacchetti di NuGet.

Il codice del file *.Program.cs del progetto AppHost per accedere al database è simile all'esempio postgreSQL:

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

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

Come il componente PostgreSQL, il componente MySQL consente anche di creare un contenitore per gli strumenti di gestione del database. L'esempio precedente aggiunge PhpMyAdmin alla soluzione.

Uso di un database MySQL

Il modello è lo stesso nei progetti che richiedono l'accesso a MySQL. Nel file Program.cs questo codice registra il database:

builder.AddMySqlDataSource("mysqldb");

Dopo aver registrato il database nel progetto di utilizzo, è possibile interagire con l'origine dati ogni volta che è necessario usando l'inserimento delle dipendenze:

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);
});

Configurazione del componente MySQL

Il componente MySQL supporta le stesse tre opzioni per gestire la configurazione.

Stringhe di connessione

Il file appsettings.json può contenere la stringa di connessione per il database MySQL:

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

Nel progetto è quindi possibile connettersi al database con la stringa di connessione usando codice simile al seguente:

builder.AddMySqlDataSource("MySqConnection");

Provider di configurazione

La chiave Aspire:MySqlConnector viene usata per configurare il componente MySQL.

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

Configurazioni inline

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

Informazioni su come eseguire il seeding del database

Lo stack .NET Aspire usa contenitori, ottenendo i vantaggi di ambienti coerenti e distribuzioni semplici. Uno svantaggio è che i contenitori sono senza stato. Tutti i dati o gli schemi aggiunti a un database vengono persi quando il contenitore viene eliminato definitivamente. .NET Aspire offre modi per eseguire il seeding dei database con i dati quando crea i contenitori.

Uso di volumi e script

Il modo più semplice per eseguire il seeding del database consiste nell'usare volumi e script SQL. I volumi possono archiviare i dati per più contenitori alla volta, offrire prestazioni elevate e semplificare il backup o la migrazione. Gli script archiviati in questi volumi vengono eseguiti quando viene creato un contenitore, popolando il database con i dati. Lo script può essere un file SQL che contiene i dati e lo schema desiderati per il database.

Ad esempio, se si dispone di questo script SQL, archiviato in un file denominato postgres-backup.sql, nella cartella 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);

Nell'host dell'app della soluzione è possibile associare la cartella Service.API/Seed alla cartella /docker-entrypoint-initdb.d del contenitore. Questa cartella è una cartella speciale nel contenitore PostgreSQL che esegue qualsiasi script SQL trovato quando viene creato il contenitore:

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

È anche possibile suddividere gli script SQL in script di creazione dello schema e seeding dei dati. Se sono tutti contenuti nella cartella Service.API/Seed, vengono eseguiti quando .NET Aspire crea il database.

Seeding dei dati con Entity Framework Core

Per i componenti che supportano Entity Framework Core, è possibile eseguire il seeding del database usando la classe DbContext e le migrazioni di base di Entity Framework. Questo metodo usa il codice C# per eseguire il seeding del database. Tuttavia, questo seeding deve essere eseguito solo durante lo sviluppo o il test, non nell'ambiente di produzione.

// 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();
    }
}

Il codice precedente controlla lo stato dell'ambiente dell'app. Se è in fase di sviluppo, il codice recupera la classe CatalogContext ed esegue il metodo EnsureCreated. Questo metodo crea il database ed esegue tutte le migrazioni in sospeso.

Per altre informazioni su come eseguire il seeding dei diversi componenti di database, vedere la documentazione di .NET Aspire.