Condividi tramite


Creare un'API Web con ASP.NET Core e MongoDB

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Di Pratik Khandelwal e Scott Addie

Questa esercitazione crea un'API Web che esegue operazioni Create, Read, Update e Delete (CRUD) in un database NoSQL mongoDB .

In questa esercitazione apprenderai a:

  • Configurare MongoDB
  • Creare un database MongoDB
  • Definire una raccolta e uno schema MongoDB
  • Eseguire operazioni CRUD di MongoDB da un'API Web
  • Personalizzare la serializzazione JSON

Prerequisiti

Configurare MongoDB

Abilitare l'accesso alla shell MongoDB e MongoDB da qualsiasi punto del computer di sviluppo (Windows/Linux/macOS):

  1. Scaricare e installare MongoDB Shell:

    • macOS/Linux: Selezionare una directory in cui estrarre la MongoDB Shell. Aggiungere il percorso risultante per mongosh alla PATH variabile di ambiente.
    • Windows: MongoDB Shell (mongosh.exe) è installato in C:\Users\<user>\AppData\Local\Programs\mongosh. Aggiungere il percorso risultante per mongosh.exe alla PATH variabile di ambiente.
  2. Scaricare e installare MongoDB:

    • macOS/Linux: verificare la directory dove è installato MongoDB, di solito in /usr/local/mongodb. Aggiungere il percorso risultante per mongodb alla PATH variabile di ambiente.
    • Windows: MongoDB è installato in C:\Programmi\MongoDB per impostazione predefinita. Aggiungere C:\Programmi\MongoDB\Server\<version_number>\bin alla PATH variabile di ambiente.
  3. Scegliere una directory di archiviazione dati: selezionare una directory nel computer di sviluppo per l'archiviazione dei dati. Crea la directory se non esiste. La shell mongoDB non crea nuove directory:

    • macOS/Linux: ad esempio. /usr/local/var/mongodb
    • Windows: ad esempio. C:\\BooksData
  4. Nella shell dei comandi del sistema operativo (non nella shell mongoDB) usare il comando seguente per connettersi a MongoDB sulla porta predefinita 27017. Sostituire <data_directory_path> con la directory scelta nel passaggio precedente.

    mongod --dbpath <data_directory_path>
    

Usare la shell MongoDB installata in precedenza nei passaggi seguenti per creare un database, creare raccolte e archiviare documenti. Per altre informazioni sui comandi della shell mongoDB, vedere mongosh.

  1. Aprire un'istanza della shell dei comandi di MongoDB avviando mongosh.exeo eseguendo il comando seguente nella shell dei comandi:

    mongosh
    
  2. Nella shell dei comandi connettersi al database di test predefinito eseguendo:

    use BookStore
    

    Se non esiste già, viene creato un database denominato BookStore . Se il database esiste, la connessione viene aperta per le transazioni.

  3. Creare una raccolta Books tramite il comando seguente:

    db.createCollection('Books')
    

    Viene visualizzato il risultato seguente:

    { "ok" : 1 }
    
  4. Definire uno schema per la raccolta Books e inserire due documenti usando il comando seguente:

    db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
    

    Viene visualizzato un risultato simile al seguente:

    {
        "acknowledged" : true,
        "insertedIds" : [
            ObjectId("61a6058e6c43f32854e51f51"),
            ObjectId("61a6058e6c43f32854e51f52")
         ]
     }
    

    Nota

    I ObjectIdvalori visualizzati nel risultato precedente non corrispondono a quelli visualizzati nella shell dei comandi.

  5. Visualizzare i documenti nel database usando il comando seguente:

    db.Books.find().pretty()
    

    Viene visualizzato un risultato simile al seguente:

    {
         "_id" : ObjectId("61a6058e6c43f32854e51f51"),
         "Name" : "Design Patterns",
         "Price" : 54.93,
         "Category" : "Computers",
         "Author" : "Ralph Johnson"
     }
     {
         "_id" : ObjectId("61a6058e6c43f32854e51f52"),
         "Name" : "Clean Code",
         "Price" : 43.15,
         "Category" : "Computers",
         "Author" : "Robert C. Martin"
     }
    

    Lo schema aggiunge una proprietà _id generata automaticamente di tipo ObjectId per ogni documento.

Creare il progetto per l'API Web ASP.NET Core

  1. Passare a File>Nuovo>Progetto.
  2. Selezionare il tipo di progetto API Web core ASP.NET e selezionare Avanti.
  3. Assegnare al progetto il nome BookStoreApi e selezionare Avanti.
  4. Nella finestra di dialogo informazioni aggiuntive:
  • Verificare che il Framework sia .NET 9.0 (Supporto Standard).
  • Verificare che sia selezionata la casella di controllo Usa controller.
  • Verificare che sia selezionata la casella di controllo per Abilitare il supporto OpenAPI.
  • Selezionare Crea.
  1. Nella finestra Console di Gestione pacchetti passare alla radice del progetto. Eseguire il comando seguente per installare il driver .NET per MongoDB:

    Install-Package MongoDB.Driver
    

Aggiungere un modello di entità

  1. Aggiungere una directory Models alla radice del progetto.

  2. Aggiungere una classe Book alla directory Models con il codice seguente:

    using MongoDB.Bson;
    using MongoDB.Bson.Serialization.Attributes;
    
    namespace BookStoreApi.Models;
    
    public class Book
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string? Id { get; set; }
    
        [BsonElement("Name")]
        public string BookName { get; set; } = null!;
    
        public decimal Price { get; set; }
    
        public string Category { get; set; } = null!;
    
        public string Author { get; set; } = null!;
    }
    

    Nella classe precedente la Id proprietà è:

    • Obbligatorio per eseguire il mapping dell'oggetto Common Language Runtime (CLR) alla collezione MongoDB.
    • Annotato con [BsonId] per impostare questa proprietà come chiave primaria del documento.
    • Annotato con [BsonRepresentation(BsonType.ObjectId)] per consentire il passaggio del parametro come tipo string invece di una struttura ObjectId . Mongo gestisce la conversione da string a ObjectId.

    La BookName proprietà viene annotata con l'attributo [BsonElement] . Il valore dell'attributo Name rappresenta il nome della proprietà nella raccolta MongoDB.

Aggiungere un modello di configurazione

  1. Aggiungere i valori di configurazione del database seguenti a appsettings.json:

    {
      "BookStoreDatabase": {
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookStore",
        "BooksCollectionName": "Books"
      },
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*"
    }
    
  2. Aggiungere una classe BookStoreDatabaseSettings alla directory Models con il codice seguente:

    namespace BookStoreApi.Models;
    
    public class BookStoreDatabaseSettings
    {
        public string ConnectionString { get; set; } = null!;
    
        public string DatabaseName { get; set; } = null!;
    
        public string BooksCollectionName { get; set; } = null!;
    }
    

    La classe precedente BookStoreDatabaseSettings viene usata per archiviare i appsettings.json valori delle proprietà del BookStoreDatabase file. I nomi delle proprietà JSON e C# sono identici per semplificare il processo di mapping.

  3. Aggiungere il codice evidenziato seguente a Program.cs:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    

    Nel codice precedente, l'istanza di configurazione a cui viene associata la sezione appsettings.json del file BookStoreDatabase viene registrata nel contenitore di Iniezione delle dipendenze. Ad esempio, la BookStoreDatabaseSettings proprietà dell'oggetto ConnectionString viene popolata con la BookStoreDatabase:ConnectionString proprietà in appsettings.json.

  4. Aggiungere il codice seguente all'inizio di Program.cs per risolvere il BookStoreDatabaseSettings riferimento:

    using BookStoreApi.Models;
    

Aggiungere un servizio di operazioni CRUD

  1. Aggiungere una directory Services alla radice del progetto.

  2. Aggiungere una classe BooksService alla directory Services con il codice seguente:

    using BookStoreApi.Models;
    using Microsoft.Extensions.Options;
    using MongoDB.Driver;
    
    namespace BookStoreApi.Services;
    
    public class BooksService
    {
        private readonly IMongoCollection<Book> _booksCollection;
    
        public BooksService(
            IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
        {
            var mongoClient = new MongoClient(
                bookStoreDatabaseSettings.Value.ConnectionString);
    
            var mongoDatabase = mongoClient.GetDatabase(
                bookStoreDatabaseSettings.Value.DatabaseName);
    
            _booksCollection = mongoDatabase.GetCollection<Book>(
                bookStoreDatabaseSettings.Value.BooksCollectionName);
        }
    
        public async Task<List<Book>> GetAsync() =>
            await _booksCollection.Find(_ => true).ToListAsync();
    
        public async Task<Book?> GetAsync(string id) =>
            await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync();
    
        public async Task CreateAsync(Book newBook) =>
            await _booksCollection.InsertOneAsync(newBook);
    
        public async Task UpdateAsync(string id, Book updatedBook) =>
            await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook);
    
        public async Task RemoveAsync(string id) =>
            await _booksCollection.DeleteOneAsync(x => x.Id == id);
    }
    

    Nel codice precedente, un'istanza BookStoreDatabaseSettings viene recuperata tramite l'iniezione delle dipendenze nel costruttore. Questa tecnica consente di accedere ai valori di appsettings.json configurazione aggiunti nella sezione Aggiungere un modello di configurazione.

  3. Aggiungere il codice evidenziato seguente a Program.cs:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    
    builder.Services.AddSingleton<BooksService>();
    

    Nel codice precedente, la classe BooksService è registrata tramite Inversione di dipendenze per abilitare l'iniezione del costruttore nelle classi che la utilizzano. La durata del servizio singleton è più appropriata perché BooksService assume una dipendenza diretta a MongoClient. In base alle linee guida per il riutilizzo di Mongo Client ufficiali, MongoClient deve essere registrato nell'inserimento di dipendenze con un ciclo di vita del servizio singleton.

  4. Aggiungere il codice seguente all'inizio di Program.cs per risolvere il BooksService riferimento:

    using BookStoreApi.Services;
    

La BooksService classe usa i membri seguenti MongoDB.Driver per eseguire operazioni CRUD sul database:

  • MongoClient: legge l'istanza del server per l'esecuzione di operazioni di database. Il costruttore di questa classe viene fornito nella stringa di connessione MongoDB.

    public BooksService(
        IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
    {
        var mongoClient = new MongoClient(
            bookStoreDatabaseSettings.Value.ConnectionString);
    
        var mongoDatabase = mongoClient.GetDatabase(
            bookStoreDatabaseSettings.Value.DatabaseName);
    
        _booksCollection = mongoDatabase.GetCollection<Book>(
            bookStoreDatabaseSettings.Value.BooksCollectionName);
    }
    
  • IMongoDatabase: rappresenta il database Mongo per l'esecuzione delle operazioni. Questa esercitazione usa il metodo getCollection<TDocument>(collection) generico sull'interfaccia per ottenere l'accesso ai dati in una raccolta specifica. Eseguire operazioni CRUD sulla raccolta dopo che questo metodo viene chiamato. Nella chiamata del metodo GetCollection<TDocument>(collection):

    • collection rappresenta il nome della raccolta.
    • TDocument rappresenta il tipo di oggetto CLR archiviato nella raccolta.

GetCollection<TDocument>(collection) restituisce un oggetto MongoCollection che rappresenta la raccolta. In questo tutorial, vengono richiamati i metodi seguenti sulla raccolta:

  • DeleteOneAsync: elimina un singolo documento corrispondente ai criteri di ricerca specificati.
  • Trova<TDocument>: restituisce tutti i documenti nella raccolta che corrispondono ai criteri di ricerca specificati.
  • InsertOneAsync: inserisce l'oggetto fornito come nuovo documento nell'insieme.
  • ReplaceOneAsync: sostituisce il singolo documento corrispondente ai criteri di ricerca specificati con l'oggetto specificato.

Aggiungere un controller

Aggiungere una classe BooksController alla directory Controllers con il codice seguente:

using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace BookStoreApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    private readonly BooksService _booksService;

    public BooksController(BooksService booksService) =>
        _booksService = booksService;

    [HttpGet]
    public async Task<List<Book>> Get() =>
        await _booksService.GetAsync();

    [HttpGet("{id:length(24)}")]
    public async Task<ActionResult<Book>> Get(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        return book;
    }

    [HttpPost]
    public async Task<IActionResult> Post(Book newBook)
    {
        await _booksService.CreateAsync(newBook);

        return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
    }

    [HttpPut("{id:length(24)}")]
    public async Task<IActionResult> Update(string id, Book updatedBook)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public async Task<IActionResult> Delete(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

Il controller dell'API Web precedente:

  • Usa la BooksService classe per eseguire operazioni CRUD.
  • Contiene metodi di azione per supportare le richieste HTTP GET, POST, PUT e DELETE.
  • Chiama CreatedAtAction nel metodo dell'azione Create per restituire una risposta HTTP 201. Il codice di stato 201 è la risposta standard per un metodo HTTP POST che crea una nuova risorsa nel server. CreatedAtAction aggiunge anche un'intestazione Location alla risposta. L'intestazione Location specifica l'URI del libro appena creato.

Configurare le opzioni di serializzazione JSON

Esistono due dettagli da modificare per le risposte JSON restituite nella sezione Testare l'API Web:

  • La notazione a cammello predefinita per i nomi di proprietà deve essere modificata in modo da adottare la convenzione Pascal dei nomi di proprietà dell'oggetto CLR.
  • La proprietà bookName deve essere restituita come Name.

Per soddisfare i requisiti precedenti, apportare le modifiche seguenti:

  1. In Program.cs concatenare il codice evidenziato seguente alla chiamata del metodo AddControllers:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    
    builder.Services.AddSingleton<BooksService>();
    
    builder.Services.AddControllers()
        .AddJsonOptions(
            options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
    

    Con la modifica precedente, i nomi delle proprietà nella risposta JSON serializzata dell'API Web corrispondono ai nomi di proprietà corrispondenti nel tipo di oggetto CLR. Ad esempio, la Book proprietà della Author classe serializza come Author anziché author.

  2. In Models/Book.csannotare la BookName proprietà con l'attributo [JsonPropertyName] :

    [BsonElement("Name")]
    [JsonPropertyName("Name")]
    public string BookName { get; set; } = null!;
    

    Il valore [JsonPropertyName] dell'attributo Name rappresenta il nome della proprietà nella risposta JSON serializzata dell'API Web.

  3. Aggiungere il codice seguente all'inizio di Models/Book.cs per risolvere il riferimento all'attributo [JsonProperty] :

    using System.Text.Json.Serialization;
    
  4. Ripetere i passaggi definiti nella sezione Testare l'API Web. Si noti la differenza nei nomi di proprietà JSON.

Testare l'API Web

Questa esercitazione usa Endpoints Explorer e i file .http per testare l'API.

  1. Compilare ed eseguire l'app.

  2. In Esplora endpoint fare clic con il pulsante destro del mouse sul primo endpoint /api/booksGET e selezionare Genera richiesta.

    Al file viene aggiunto il BookStoreApi.http contenuto seguente. Se è la prima volta che viene generata una richiesta, il file viene creato nella radice del progetto.

    @BookStoreApi_HostAddress = https://localhost:<port>
    
    GET {{BookStoreApi_HostAddress}}/api/books
    
    ###
    

    Il numero di porta deve essere già impostato sulla porta usata dall'app, ad esempio https://localhost:56874. In caso contrario, è possibile trovare il numero di porta nella finestra di output quando si avvia l'app.

  3. Selezionare il collegamento Invia richiesta sopra la nuova GET riga di richiesta.

    La richiesta GET viene inviata all'app e la risposta viene visualizzata nel riquadro Risposta .

  4. Il corpo della risposta mostra il risultato JSON contenente le voci del libro simili alle seguenti:

    [
      {
        "Id": "61a6058e6c43f32854e51f51",
        "Name": "Design Patterns",
        "Price": 54.93,
        "Category": "Computers",
        "Author": "Ralph Johnson"
      },
      {
        "Id": "61a6058e6c43f32854e51f52",
        "Name": "Clean Code",
        "Price": 43.15,
        "Category": "Computers",
        "Author": "Robert C. Martin"
      }
    ]
    
  5. Per recuperare un singolo libro, fare clic con il pulsante destro del mouse sull'endpoint /api/books/{id}, params (string id)GET in Esplora endpoint e scegliere Genera richiesta.

    Il contenuto seguente viene aggiunto al BookStoreApi.http file:

    @id=string
    GET {{BookStoreApi_HostAddress}}/api/books/{{id}}
    
    ###
    
  6. Sostituire id la variabile con uno degli ID restituiti dalla richiesta precedente, ad esempio:

    @id="61a6058e6c43f32854e51f52"
    GET {{BookStoreApi_HostAddress}}/api/books/{{id}}
    
    ###
    
  7. Selezionare il collegamento Invia richiesta sopra la nuova GET riga di richiesta.

    La richiesta GET viene inviata all'app e la risposta viene visualizzata nel riquadro Risposta .

  8. Il corpo della risposta mostra un JSON simile al seguente:

    {
      "Id": "61a6058e6c43f32854e51f52",
      "Name": "Clean Code",
      "Price": 43.15,
      "Category": "Computers",
      "Author": "Robert C. Martin"
    }
    
  9. Per testare l'endpoint POST, fare clic con il pulsante destro del mouse sull'endpoint /api/booksPOST e selezionare Genera richiesta.

    Al file viene aggiunto il BookStoreApi.http contenuto seguente:

    POST {{BookStoreApi_HostAddress}}/api/books
    Content-Type: application/json
    
    {
      //Book
    }
    
    ###
    
  10. Sostituire il commento Book con un oggetto book come corpo della richiesta JSON:

    POST {{BookStoreApi_HostAddress}}/api/books
    Content-Type: application/json
    
     {
       "Name": "The Pragmatic Programmer",
       "Price": 49.99,
       "Category": "Computers",
       "Author": "Andy Hunt"
     }
    
    ###
    
  11. Selezionare il collegamento Invia richiesta sopra la riga della POST richiesta.

    La richiesta POST viene inviata all'app e la risposta viene visualizzata nel riquadro Risposta . La risposta deve includere il libro appena creato con l'ID assegnato.

  12. Infine, per eliminare un libro, fare clic con il pulsante destro del mouse sull'endpoint /api/books/{id}, params (string id)DELETE e selezionare Genera richiesta.

    Il contenuto seguente viene aggiunto al BookStoreApi.http file:

    DELETE {{BookStoreApi_HostAddress}}/api/Books/{{id}}
    
    ###
    
  13. Sostituire la id variabile con uno degli ID restituiti dalla richiesta precedente e fare clic su Invia richiesta. Per esempio:

    DELETE {{BookStoreApi_HostAddress}}/api/Books/67f417517ce1b36aeab71236
    
    ###
    

Aggiungere il supporto per l'autenticazione a un'API Web

ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web ASP.NET Core. Per proteggere le API web e le applicazioni a pagina singola, usare una delle opzioni seguenti:

Duende Identity Server è un framework OpenID Connect e OAuth 2.0 per ASP.NET Core. Duende Identity Server abilita le funzionalità di sicurezza seguenti:

  • Autenticazione come servizio (AaaS)
  • Single Sign-On/off (SSO) su più tipi di applicazione
  • Controllo di accesso per le API
  • Gateway federativo

Importante

Duende Software potrebbe richiedere il pagamento di una tariffa di licenza per l'uso in produzione di Duende Identity Server. Per altre informazioni, vedere Eseguire la migrazione da ASP.NET Core 5.0 a 6.0.

Per altre informazioni, vedere la documentazione di Duende Server (sito Web duende Identity Software).

Risorse aggiuntive

Questa esercitazione crea un'API Web che esegue operazioni Create, Read, Update e Delete (CRUD) in un database NoSQL mongoDB .

In questa esercitazione apprenderai a:

  • Configurare MongoDB
  • Creare un database MongoDB
  • Definire una raccolta e uno schema MongoDB
  • Eseguire operazioni CRUD di MongoDB da un'API Web
  • Personalizzare la serializzazione JSON

Prerequisiti

Configurare MongoDB

Abilitare l'accesso alla shell MongoDB e MongoDB da qualsiasi punto del computer di sviluppo (Windows/Linux/macOS):

  1. Scaricare e installare MongoDB Shell:

    • macOS/Linux: Scegli una directory in cui estrarre la Shell MongoDB. Aggiungere il percorso risultante per mongosh alla PATH variabile di ambiente.
    • Windows: MongoDB Shell (mongosh.exe) è installato in C:\Users\<user>\AppData\Local\Programs\mongosh. Aggiungere il percorso risultante per mongosh.exe alla PATH variabile di ambiente.
  2. Scaricare e installare MongoDB:

    • macOS/Linux: verificare la directory dove è installato MongoDB, di solito in /usr/local/mongodb. Aggiungere il percorso risultante per mongodb alla PATH variabile di ambiente.
    • Windows: MongoDB è installato in C:\Programmi\MongoDB per impostazione predefinita. Aggiungere C:\Programmi\MongoDB\Server\<version_number>\bin alla PATH variabile di ambiente.
  3. Scegliere una directory di archiviazione dati: selezionare una directory nel computer di sviluppo per l'archiviazione dei dati. Crea la directory se non esiste. La shell mongoDB non crea nuove directory:

    • macOS/Linux: ad esempio. /usr/local/var/mongodb
    • Windows: ad esempio. C:\\BooksData
  4. Nella shell dei comandi del sistema operativo (non nella shell mongoDB) usare il comando seguente per connettersi a MongoDB sulla porta predefinita 27017. Sostituire <data_directory_path> con la directory scelta nel passaggio precedente.

    mongod --dbpath <data_directory_path>
    

Usare la shell MongoDB installata in precedenza nei passaggi seguenti per creare un database, creare raccolte e archiviare documenti. Per altre informazioni sui comandi della shell mongoDB, vedere mongosh.

  1. Aprire un'istanza della shell dei comandi di MongoDB avviando mongosh.exeo eseguendo il comando seguente nella shell dei comandi:

    mongosh
    
  2. Nella shell dei comandi connettersi al database di test predefinito eseguendo:

    use BookStore
    

    Se non esiste già, viene creato un database denominato BookStore . Se il database esiste, la connessione viene aperta per le transazioni.

  3. Creare una raccolta Books tramite il comando seguente:

    db.createCollection('Books')
    

    Viene visualizzato il risultato seguente:

    { "ok" : 1 }
    
  4. Definire uno schema per la raccolta Books e inserire due documenti usando il comando seguente:

    db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
    

    Viene visualizzato un risultato simile al seguente:

    {
        "acknowledged" : true,
        "insertedIds" : [
            ObjectId("61a6058e6c43f32854e51f51"),
            ObjectId("61a6058e6c43f32854e51f52")
         ]
     }
    

    Nota

    I ObjectIdvalori visualizzati nel risultato precedente non corrispondono a quelli visualizzati nella shell dei comandi.

  5. Visualizzare i documenti nel database usando il comando seguente:

    db.Books.find().pretty()
    

    Viene visualizzato un risultato simile al seguente:

    {
         "_id" : ObjectId("61a6058e6c43f32854e51f51"),
         "Name" : "Design Patterns",
         "Price" : 54.93,
         "Category" : "Computers",
         "Author" : "Ralph Johnson"
     }
     {
         "_id" : ObjectId("61a6058e6c43f32854e51f52"),
         "Name" : "Clean Code",
         "Price" : 43.15,
         "Category" : "Computers",
         "Author" : "Robert C. Martin"
     }
    

    Lo schema aggiunge una proprietà _id generata automaticamente di tipo ObjectId per ogni documento.

Creare il progetto per l'API Web ASP.NET Core

  1. Vai a File>Nuovo>Progetto.

  2. Selezionare il tipo di progetto API Web core ASP.NET e selezionare Avanti.

  3. Assegnare al progetto il nome BookStoreApi e selezionare Avanti.

  4. Selezionare il framework .NET 8.0 (supporto a lungo termine) e selezionare Crea.

  5. Nella finestra Console di Gestione pacchetti passare alla radice del progetto. Eseguire il comando seguente per installare il driver .NET per MongoDB:

    Install-Package MongoDB.Driver
    

Aggiungere un modello di entità

  1. Aggiungere una directory Models alla radice del progetto.

  2. Aggiungere una classe Book alla directory Models con il codice seguente:

    using MongoDB.Bson;
    using MongoDB.Bson.Serialization.Attributes;
    
    namespace BookStoreApi.Models;
    
    public class Book
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string? Id { get; set; }
    
        [BsonElement("Name")]
        public string BookName { get; set; } = null!;
    
        public decimal Price { get; set; }
    
        public string Category { get; set; } = null!;
    
        public string Author { get; set; } = null!;
    }
    

    Nella classe precedente la Id proprietà è:

    • Obbligatorio per eseguire il mapping dell'oggetto Common Language Runtime (CLR) alla collezione MongoDB.
    • Annotato con [BsonId] per impostare questa proprietà come chiave primaria del documento.
    • Annotato con [BsonRepresentation(BsonType.ObjectId)] per consentire il passaggio del parametro come tipo string invece di una struttura ObjectId . Mongo gestisce la conversione da string a ObjectId.

    La BookName proprietà viene annotata con l'attributo [BsonElement] . Il valore dell'attributo Name rappresenta il nome della proprietà nella raccolta MongoDB.

Aggiungere un modello di configurazione

  1. Aggiungere i valori di configurazione del database seguenti a appsettings.json:

    {
      "BookStoreDatabase": {
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookStore",
        "BooksCollectionName": "Books"
      },
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*"
    }
    
  2. Aggiungere una classe BookStoreDatabaseSettings alla directory Models con il codice seguente:

    namespace BookStoreApi.Models;
    
    public class BookStoreDatabaseSettings
    {
        public string ConnectionString { get; set; } = null!;
    
        public string DatabaseName { get; set; } = null!;
    
        public string BooksCollectionName { get; set; } = null!;
    }
    

    La classe precedente BookStoreDatabaseSettings viene usata per archiviare i appsettings.json valori delle proprietà del BookStoreDatabase file. I nomi delle proprietà JSON e C# sono identici per semplificare il processo di mapping.

  3. Aggiungere il codice evidenziato seguente a Program.cs:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    

    Nel codice precedente, l'istanza di configurazione a cui viene associata la sezione appsettings.json del file BookStoreDatabase viene registrata nel contenitore di Iniezione delle dipendenze. Ad esempio, la BookStoreDatabaseSettings proprietà dell'oggetto ConnectionString viene popolata con la BookStoreDatabase:ConnectionString proprietà in appsettings.json.

  4. Aggiungere il codice seguente all'inizio di Program.cs per risolvere il BookStoreDatabaseSettings riferimento:

    using BookStoreApi.Models;
    

Aggiungere un servizio di operazioni CRUD

  1. Aggiungere una directory Services alla radice del progetto.

  2. Aggiungere una classe BooksService alla directory Services con il codice seguente:

    using BookStoreApi.Models;
    using Microsoft.Extensions.Options;
    using MongoDB.Driver;
    
    namespace BookStoreApi.Services;
    
    public class BooksService
    {
        private readonly IMongoCollection<Book> _booksCollection;
    
        public BooksService(
            IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
        {
            var mongoClient = new MongoClient(
                bookStoreDatabaseSettings.Value.ConnectionString);
    
            var mongoDatabase = mongoClient.GetDatabase(
                bookStoreDatabaseSettings.Value.DatabaseName);
    
            _booksCollection = mongoDatabase.GetCollection<Book>(
                bookStoreDatabaseSettings.Value.BooksCollectionName);
        }
    
        public async Task<List<Book>> GetAsync() =>
            await _booksCollection.Find(_ => true).ToListAsync();
    
        public async Task<Book?> GetAsync(string id) =>
            await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync();
    
        public async Task CreateAsync(Book newBook) =>
            await _booksCollection.InsertOneAsync(newBook);
    
        public async Task UpdateAsync(string id, Book updatedBook) =>
            await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook);
    
        public async Task RemoveAsync(string id) =>
            await _booksCollection.DeleteOneAsync(x => x.Id == id);
    }
    

    Nel codice precedente, un'istanza BookStoreDatabaseSettings viene recuperata dall'inserimento delle dipendenze tramite l'inserimento del costruttore. Questa tecnica consente di accedere ai valori di appsettings.json configurazione aggiunti nella sezione Aggiungere un modello di configurazione.

  3. Aggiungere il codice evidenziato seguente a Program.cs:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    
    builder.Services.AddSingleton<BooksService>();
    

    Nel codice precedente la classe BooksService è registrata con l'inserimento di dipendenze per supportare l'inserimento del costruttore nelle classi che la utilizzano. La durata del servizio singleton è più appropriata perché BooksService assume una dipendenza diretta a MongoClient. In base alle linee guida per il riutilizzo di Mongo Client ufficiali, MongoClient deve essere registrato nell'inserimento di dipendenze con un ciclo di vita del servizio singleton.

  4. Aggiungere il codice seguente all'inizio di Program.cs per risolvere il BooksService riferimento:

    using BookStoreApi.Services;
    

La BooksService classe usa i membri seguenti MongoDB.Driver per eseguire operazioni CRUD sul database:

  • MongoClient: legge l'istanza del server per l'esecuzione di operazioni di database. Il costruttore di questa classe viene fornito nella stringa di connessione MongoDB.

    public BooksService(
        IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
    {
        var mongoClient = new MongoClient(
            bookStoreDatabaseSettings.Value.ConnectionString);
    
        var mongoDatabase = mongoClient.GetDatabase(
            bookStoreDatabaseSettings.Value.DatabaseName);
    
        _booksCollection = mongoDatabase.GetCollection<Book>(
            bookStoreDatabaseSettings.Value.BooksCollectionName);
    }
    
  • IMongoDatabase: rappresenta il database Mongo per l'esecuzione delle operazioni. Questa esercitazione usa il metodo getCollection<TDocument>(collection) generico sull'interfaccia per ottenere l'accesso ai dati in una raccolta specifica. Eseguire operazioni CRUD sulla raccolta dopo che questo metodo viene chiamato. Nella chiamata del metodo GetCollection<TDocument>(collection):

    • collection rappresenta il nome della raccolta.
    • TDocument rappresenta il tipo di oggetto CLR archiviato nella raccolta.

GetCollection<TDocument>(collection) restituisce un oggetto MongoCollection che rappresenta la raccolta. In questa guida, vengono richiamati i seguenti metodi sulla raccolta:

  • DeleteOneAsync: elimina un singolo documento corrispondente ai criteri di ricerca specificati.
  • Trova<TDocument>: restituisce tutti i documenti nella raccolta che corrispondono ai criteri di ricerca specificati.
  • InsertOneAsync: inserisce l'oggetto fornito come nuovo documento nell'insieme.
  • ReplaceOneAsync: sostituisce il singolo documento corrispondente ai criteri di ricerca specificati con l'oggetto specificato.

Aggiungere un controller

Aggiungere una classe BooksController alla directory Controllers con il codice seguente:

using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace BookStoreApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    private readonly BooksService _booksService;

    public BooksController(BooksService booksService) =>
        _booksService = booksService;

    [HttpGet]
    public async Task<List<Book>> Get() =>
        await _booksService.GetAsync();

    [HttpGet("{id:length(24)}")]
    public async Task<ActionResult<Book>> Get(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        return book;
    }

    [HttpPost]
    public async Task<IActionResult> Post(Book newBook)
    {
        await _booksService.CreateAsync(newBook);

        return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
    }

    [HttpPut("{id:length(24)}")]
    public async Task<IActionResult> Update(string id, Book updatedBook)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public async Task<IActionResult> Delete(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

Il controller dell'API Web precedente:

  • Usa la BooksService classe per eseguire operazioni CRUD.
  • Contiene metodi di azione per supportare le richieste HTTP GET, POST, PUT e DELETE.
  • Chiama CreatedAtAction nel metodo dell'azione Create per restituire una risposta HTTP 201. Il codice di stato 201 è la risposta standard per un metodo HTTP POST che crea una nuova risorsa nel server. CreatedAtAction aggiunge anche un'intestazione Location alla risposta. L'intestazione Location specifica l'URI del libro appena creato.

Testare l'API Web

  1. Compilare ed eseguire l'app.

  2. Passare a https://localhost:<port>/api/books, dove <port> è il numero di porta assegnato automaticamente per l'app, per testare il metodo di azione senza Get parametri del controller. Viene visualizzata una risposta JSON simile alla seguente:

    [
      {
        "id": "61a6058e6c43f32854e51f51",
        "bookName": "Design Patterns",
        "price": 54.93,
        "category": "Computers",
        "author": "Ralph Johnson"
      },
      {
        "id": "61a6058e6c43f32854e51f52",
        "bookName": "Clean Code",
        "price": 43.15,
        "category": "Computers",
        "author": "Robert C. Martin"
      }
    ]
    
  3. Passare a https://localhost:<port>/api/books/{id here} per testare il metodo azione sovraccaricato Get del controller. Viene visualizzata una risposta JSON simile alla seguente:

    {
      "id": "61a6058e6c43f32854e51f52",
      "bookName": "Clean Code",
      "price": 43.15,
      "category": "Computers",
      "author": "Robert C. Martin"
    }
    

Configurare le opzioni di serializzazione JSON

Esistono due dettagli da modificare per le risposte JSON restituite nella sezione Testare l'API Web:

  • La notazione a cammello predefinita per i nomi di proprietà deve essere modificata in modo da adottare la convenzione Pascal dei nomi di proprietà dell'oggetto CLR.
  • La proprietà bookName deve essere restituita come Name.

Per soddisfare i requisiti precedenti, apportare le modifiche seguenti:

  1. In Program.cs concatenare il codice evidenziato seguente alla chiamata del metodo AddControllers:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    
    builder.Services.AddSingleton<BooksService>();
    
    builder.Services.AddControllers()
        .AddJsonOptions(
            options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
    

    Con la modifica precedente, i nomi delle proprietà nella risposta JSON serializzata dell'API Web corrispondono ai nomi di proprietà corrispondenti nel tipo di oggetto CLR. Ad esempio, la Book proprietà della Author classe serializza come Author anziché author.

  2. In Models/Book.csannotare la BookName proprietà con l'attributo [JsonPropertyName] :

    [BsonElement("Name")]
    [JsonPropertyName("Name")]
    public string BookName { get; set; } = null!;
    

    Il valore [JsonPropertyName] dell'attributo Name rappresenta il nome della proprietà nella risposta JSON serializzata dell'API Web.

  3. Aggiungere il codice seguente all'inizio di Models/Book.cs per risolvere il riferimento all'attributo [JsonProperty] :

    using System.Text.Json.Serialization;
    
  4. Ripetere i passaggi definiti nella sezione Testare l'API Web. Si noti la differenza nei nomi di proprietà JSON.

Aggiungere il supporto per l'autenticazione a un'API Web

ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web ASP.NET Core. Per proteggere le API web e le applicazioni a pagina singola, usare una delle opzioni seguenti:

Duende Identity Server è un framework OpenID Connect e OAuth 2.0 per ASP.NET Core. Duende Identity Server abilita le funzionalità di sicurezza seguenti:

  • Autenticazione come servizio (AaaS)
  • Single Sign-On/off (SSO) su più tipi di applicazione
  • Controllo di accesso per le API
  • Gateway federativo

Importante

Duende Software potrebbe richiedere il pagamento di una tariffa di licenza per l'uso in produzione di Duende Identity Server. Per altre informazioni, vedere Eseguire la migrazione da ASP.NET Core 5.0 a 6.0.

Per altre informazioni, vedere la documentazione di Duende Server (sito Web duende Identity Software).

Risorse aggiuntive

Questa esercitazione crea un'API Web che esegue operazioni Create, Read, Update e Delete (CRUD) in un database NoSQL mongoDB .

In questa esercitazione apprenderai a:

  • Configurare MongoDB
  • Creare un database MongoDB
  • Definire una raccolta e uno schema MongoDB
  • Eseguire operazioni CRUD di MongoDB da un'API Web
  • Personalizzare la serializzazione JSON

Prerequisiti

Configurare MongoDB

Abilitare l'accesso a MongoDB e Mongo DB Shell da qualsiasi punto del computer di sviluppo:

  1. In Windows MongoDB viene installato in C:\Programmi\MongoDB per impostazione predefinita. Aggiungere C:\Programmi\MongoDB\Server\<version_number>\bin alla PATH variabile di ambiente.

  2. Scaricare la shell mongoDB e scegliere una directory in cui estrarla. Aggiungere il percorso risultante per mongosh.exe alla PATH variabile di ambiente.

  3. Scegliere una directory nel computer di sviluppo per l'archiviazione dei dati. Ad esempio, C:\BooksData in Windows. Crea la directory se non esiste. La shell mongo non consente di creare nuove directory.

  4. Nella shell dei comandi del sistema operativo (non nella shell mongoDB) usare il comando seguente per connettersi a MongoDB sulla porta predefinita 27017. Sostituire <data_directory_path> con la directory scelta nel passaggio precedente.

    mongod --dbpath <data_directory_path>
    

Usare la shell MongoDB installata in precedenza nei passaggi seguenti per creare un database, creare raccolte e archiviare documenti. Per altre informazioni sui comandi della shell mongoDB, vedere mongosh.

  1. Aprire un'istanza della shell dei comandi di MongoDB avviando mongosh.exeo eseguendo il comando seguente nella shell dei comandi:

    mongosh
    
  2. Nella shell dei comandi connettersi al database di test predefinito eseguendo:

    use BookStore
    

    Se non esiste già, viene creato un database denominato BookStore . Se il database esiste, la connessione viene aperta per le transazioni.

  3. Creare una raccolta Books tramite il comando seguente:

    db.createCollection('Books')
    

    Viene visualizzato il risultato seguente:

    { "ok" : 1 }
    
  4. Definire uno schema per la raccolta Books e inserire due documenti usando il comando seguente:

    db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
    

    Viene visualizzato un risultato simile al seguente:

    {
        "acknowledged" : true,
        "insertedIds" : [
            ObjectId("61a6058e6c43f32854e51f51"),
            ObjectId("61a6058e6c43f32854e51f52")
         ]
     }
    

    Nota

    I ObjectIdvalori visualizzati nel risultato precedente non corrispondono a quelli visualizzati nella shell dei comandi.

  5. Visualizzare i documenti nel database usando il comando seguente:

    db.Books.find().pretty()
    

    Viene visualizzato un risultato simile al seguente:

    {
         "_id" : ObjectId("61a6058e6c43f32854e51f51"),
         "Name" : "Design Patterns",
         "Price" : 54.93,
         "Category" : "Computers",
         "Author" : "Ralph Johnson"
     }
     {
         "_id" : ObjectId("61a6058e6c43f32854e51f52"),
         "Name" : "Clean Code",
         "Price" : 43.15,
         "Category" : "Computers",
         "Author" : "Robert C. Martin"
     }
    

    Lo schema aggiunge una proprietà _id generata automaticamente di tipo ObjectId per ogni documento.

Creare il progetto per l'API Web ASP.NET Core

  1. Vai a File>Nuovo>Progetto.

  2. Selezionare il tipo di progetto API Web core ASP.NET e selezionare Avanti.

  3. Assegnare al progetto il nome BookStoreApi e selezionare Avanti.

  4. Selezionare il framework .NET 7.0 (Supporto termini standard) e selezionare Crea.

  5. Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti.

  6. Nella finestra Console di Gestione pacchetti passare alla radice del progetto. Eseguire il comando seguente per installare il driver .NET per MongoDB:

    Install-Package MongoDB.Driver
    

Aggiungere un modello di entità

  1. Aggiungere una directory Models alla radice del progetto.

  2. Aggiungere una classe Book alla directory Models con il codice seguente:

    using MongoDB.Bson;
    using MongoDB.Bson.Serialization.Attributes;
    
    namespace BookStoreApi.Models;
    
    public class Book
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string? Id { get; set; }
    
        [BsonElement("Name")]
        public string BookName { get; set; } = null!;
    
        public decimal Price { get; set; }
    
        public string Category { get; set; } = null!;
    
        public string Author { get; set; } = null!;
    }
    

    Nella classe precedente la Id proprietà è:

    • Obbligatorio per eseguire il mapping dell'oggetto Common Language Runtime (CLR) alla collezione MongoDB.
    • Annotato con [BsonId] per impostare questa proprietà come chiave primaria del documento.
    • Annotato con [BsonRepresentation(BsonType.ObjectId)] per consentire il passaggio del parametro come tipo string invece di una struttura ObjectId . Mongo gestisce la conversione da string a ObjectId.

    La BookName proprietà viene annotata con l'attributo [BsonElement] . Il valore dell'attributo Name rappresenta il nome della proprietà nella raccolta MongoDB.

Aggiungere un modello di configurazione

  1. Aggiungere i valori di configurazione del database seguenti a appsettings.json:

    {
      "BookStoreDatabase": {
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookStore",
        "BooksCollectionName": "Books"
      },
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*"
    }
    
  2. Aggiungere una classe BookStoreDatabaseSettings alla directory Models con il codice seguente:

    namespace BookStoreApi.Models;
    
    public class BookStoreDatabaseSettings
    {
        public string ConnectionString { get; set; } = null!;
    
        public string DatabaseName { get; set; } = null!;
    
        public string BooksCollectionName { get; set; } = null!;
    }
    

    La classe precedente BookStoreDatabaseSettings viene usata per archiviare i appsettings.json valori delle proprietà del BookStoreDatabase file. I nomi delle proprietà JSON e C# sono identici per semplificare il processo di mapping.

  3. Aggiungere il codice evidenziato seguente a Program.cs:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    

    Nel codice precedente, l'istanza di configurazione a cui viene associata la sezione appsettings.json del file BookStoreDatabase viene registrata nel contenitore di Iniezione delle dipendenze. Ad esempio, la BookStoreDatabaseSettings proprietà dell'oggetto ConnectionString viene popolata con la BookStoreDatabase:ConnectionString proprietà in appsettings.json.

  4. Aggiungere il codice seguente all'inizio di Program.cs per risolvere il BookStoreDatabaseSettings riferimento:

    using BookStoreApi.Models;
    

Aggiungere un servizio di operazioni CRUD

  1. Aggiungere una directory Services alla radice del progetto.

  2. Aggiungere una classe BooksService alla directory Services con il codice seguente:

    using BookStoreApi.Models;
    using Microsoft.Extensions.Options;
    using MongoDB.Driver;
    
    namespace BookStoreApi.Services;
    
    public class BooksService
    {
        private readonly IMongoCollection<Book> _booksCollection;
    
        public BooksService(
            IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
        {
            var mongoClient = new MongoClient(
                bookStoreDatabaseSettings.Value.ConnectionString);
    
            var mongoDatabase = mongoClient.GetDatabase(
                bookStoreDatabaseSettings.Value.DatabaseName);
    
            _booksCollection = mongoDatabase.GetCollection<Book>(
                bookStoreDatabaseSettings.Value.BooksCollectionName);
        }
    
        public async Task<List<Book>> GetAsync() =>
            await _booksCollection.Find(_ => true).ToListAsync();
    
        public async Task<Book?> GetAsync(string id) =>
            await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync();
    
        public async Task CreateAsync(Book newBook) =>
            await _booksCollection.InsertOneAsync(newBook);
    
        public async Task UpdateAsync(string id, Book updatedBook) =>
            await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook);
    
        public async Task RemoveAsync(string id) =>
            await _booksCollection.DeleteOneAsync(x => x.Id == id);
    }
    

    Nel codice precedente, un'istanza BookStoreDatabaseSettings viene recuperata dalle dipendenze tramite l'inserimento del costruttore. Questa tecnica consente di accedere ai valori di appsettings.json configurazione aggiunti nella sezione Aggiungere un modello di configurazione.

  3. Aggiungere il codice evidenziato seguente a Program.cs:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    
    builder.Services.AddSingleton<BooksService>();
    

    Nel codice precedente, la classe BooksService è registrata con DI per supportare l'iniezione del costruttore nelle classi che la utilizzano. La durata del servizio singleton è più appropriata perché BooksService assume una dipendenza diretta a MongoClient. In base alle linee guida per il riutilizzo di Mongo Client ufficiali, MongoClient deve essere registrato nell'inserimento di dipendenze con un ciclo di vita del servizio singleton.

  4. Aggiungere il codice seguente all'inizio di Program.cs per risolvere il BooksService riferimento:

    using BookStoreApi.Services;
    

La BooksService classe usa i membri seguenti MongoDB.Driver per eseguire operazioni CRUD sul database:

  • MongoClient: legge l'istanza del server per l'esecuzione di operazioni di database. Al costruttore di questa classe viene passata la stringa di connessione MongoDB:

    public BooksService(
        IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
    {
        var mongoClient = new MongoClient(
            bookStoreDatabaseSettings.Value.ConnectionString);
    
        var mongoDatabase = mongoClient.GetDatabase(
            bookStoreDatabaseSettings.Value.DatabaseName);
    
        _booksCollection = mongoDatabase.GetCollection<Book>(
            bookStoreDatabaseSettings.Value.BooksCollectionName);
    }
    
  • IMongoDatabase: rappresenta il database Mongo per l'esecuzione delle operazioni. Questa esercitazione usa il metodo getCollection<TDocument>(collection) generico sull'interfaccia per ottenere l'accesso ai dati in una raccolta specifica. Eseguire operazioni CRUD sulla raccolta dopo che questo metodo viene chiamato. Nella chiamata del metodo GetCollection<TDocument>(collection):

    • collection rappresenta il nome della raccolta.
    • TDocument rappresenta il tipo di oggetto CLR archiviato nella raccolta.

GetCollection<TDocument>(collection) restituisce un oggetto MongoCollection che rappresenta la raccolta. In questa esercitazione, vengono richiamati i metodi seguenti sulla raccolta:

  • DeleteOneAsync: elimina un singolo documento corrispondente ai criteri di ricerca specificati.
  • Trova<TDocument>: restituisce tutti i documenti nella raccolta che corrispondono ai criteri di ricerca specificati.
  • InsertOneAsync: inserisce l'oggetto fornito come nuovo documento nell'insieme.
  • ReplaceOneAsync: sostituisce il singolo documento corrispondente ai criteri di ricerca specificati con l'oggetto specificato.

Aggiungere un controller

Aggiungere una classe BooksController alla directory Controllers con il codice seguente:

using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace BookStoreApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    private readonly BooksService _booksService;

    public BooksController(BooksService booksService) =>
        _booksService = booksService;

    [HttpGet]
    public async Task<List<Book>> Get() =>
        await _booksService.GetAsync();

    [HttpGet("{id:length(24)}")]
    public async Task<ActionResult<Book>> Get(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        return book;
    }

    [HttpPost]
    public async Task<IActionResult> Post(Book newBook)
    {
        await _booksService.CreateAsync(newBook);

        return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
    }

    [HttpPut("{id:length(24)}")]
    public async Task<IActionResult> Update(string id, Book updatedBook)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public async Task<IActionResult> Delete(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

Il controller dell'API Web precedente:

  • Usa la BooksService classe per eseguire operazioni CRUD.
  • Contiene metodi di azione per supportare le richieste HTTP GET, POST, PUT e DELETE.
  • Chiama CreatedAtAction nel metodo dell'azione Create per restituire una risposta HTTP 201. Il codice di stato 201 è la risposta standard per un metodo HTTP POST che crea una nuova risorsa nel server. CreatedAtAction aggiunge anche un'intestazione Location alla risposta. L'intestazione Location specifica l'URI del libro appena creato.

Testare l'API Web

  1. Compilare ed eseguire l'app.

  2. Passare a https://localhost:<port>/api/books, dove <port> è il numero di porta assegnato automaticamente per l'app, per testare il metodo di azione senza Get parametri del controller. Viene visualizzata una risposta JSON simile alla seguente:

    [
      {
        "id": "61a6058e6c43f32854e51f51",
        "bookName": "Design Patterns",
        "price": 54.93,
        "category": "Computers",
        "author": "Ralph Johnson"
      },
      {
        "id": "61a6058e6c43f32854e51f52",
        "bookName": "Clean Code",
        "price": 43.15,
        "category": "Computers",
        "author": "Robert C. Martin"
      }
    ]
    
  3. Passare a https://localhost:<port>/api/books/{id here} per testare il metodo azione sovraccaricato Get del controller. Viene visualizzata una risposta JSON simile alla seguente:

    {
      "id": "61a6058e6c43f32854e51f52",
      "bookName": "Clean Code",
      "price": 43.15,
      "category": "Computers",
      "author": "Robert C. Martin"
    }
    

Configurare le opzioni di serializzazione JSON

Esistono due dettagli da modificare per le risposte JSON restituite nella sezione Testare l'API Web:

  • La notazione a cammello predefinita per i nomi di proprietà deve essere modificata in modo da adottare la convenzione Pascal dei nomi di proprietà dell'oggetto CLR.
  • La proprietà bookName deve essere restituita come Name.

Per soddisfare i requisiti precedenti, apportare le modifiche seguenti:

  1. In Program.cs concatenare il codice evidenziato seguente alla chiamata del metodo AddControllers:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    
    builder.Services.AddSingleton<BooksService>();
    
    builder.Services.AddControllers()
        .AddJsonOptions(
            options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
    

    Con la modifica precedente, i nomi delle proprietà nella risposta JSON serializzata dell'API Web corrispondono ai nomi di proprietà corrispondenti nel tipo di oggetto CLR. Ad esempio, la Book proprietà della Author classe serializza come Author anziché author.

  2. In Models/Book.csannotare la BookName proprietà con l'attributo [JsonPropertyName] :

    [BsonElement("Name")]
    [JsonPropertyName("Name")]
    public string BookName { get; set; } = null!;
    

    Il valore [JsonPropertyName] dell'attributo Name rappresenta il nome della proprietà nella risposta JSON serializzata dell'API Web.

  3. Aggiungere il codice seguente all'inizio di Models/Book.cs per risolvere il riferimento all'attributo [JsonProperty] :

    using System.Text.Json.Serialization;
    
  4. Ripetere i passaggi definiti nella sezione Testare l'API Web. Si noti la differenza nei nomi di proprietà JSON.

Aggiungere il supporto per l'autenticazione a un'API Web

ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web ASP.NET Core. Per proteggere le API web e le applicazioni a pagina singola, usare una delle opzioni seguenti:

Duende Identity Server è un framework OpenID Connect e OAuth 2.0 per ASP.NET Core. Duende Identity Server abilita le funzionalità di sicurezza seguenti:

  • Autenticazione come servizio (AaaS)
  • Single Sign-On/off (SSO) su più tipi di applicazione
  • Controllo di accesso per le API
  • Gateway federativo

Importante

Duende Software potrebbe richiedere il pagamento di una tariffa di licenza per l'uso in produzione di Duende Identity Server. Per altre informazioni, vedere Eseguire la migrazione da ASP.NET Core 5.0 a 6.0.

Per altre informazioni, vedere la documentazione di Duende Server (sito Web duende Identity Software).

Risorse aggiuntive

Questa esercitazione crea un'API Web che esegue operazioni Create, Read, Update e Delete (CRUD) in un database NoSQL mongoDB .

In questa esercitazione apprenderai a:

  • Configurare MongoDB
  • Creare un database MongoDB
  • Definire una raccolta e uno schema MongoDB
  • Eseguire operazioni CRUD di MongoDB da un'API Web
  • Personalizzare la serializzazione JSON

Prerequisiti

Configurare MongoDB

Abilitare l'accesso a MongoDB e Mongo DB Shell da qualsiasi punto del computer di sviluppo:

  1. In Windows MongoDB viene installato in C:\Programmi\MongoDB per impostazione predefinita. Aggiungere C:\Programmi\MongoDB\Server\<version_number>\bin alla PATH variabile di ambiente.

  2. Scaricare la shell mongoDB e scegliere una directory in cui estrarla. Aggiungere il percorso risultante per mongosh.exe alla PATH variabile di ambiente.

  3. Scegliere una directory nel computer di sviluppo per l'archiviazione dei dati. Ad esempio, C:\BooksData in Windows. Crea la directory se non esiste. La shell mongo non consente di creare nuove directory.

  4. Nella shell dei comandi del sistema operativo (non nella shell mongoDB) usare il comando seguente per connettersi a MongoDB sulla porta predefinita 27017. Sostituire <data_directory_path> con la directory scelta nel passaggio precedente.

    mongod --dbpath <data_directory_path>
    

Usare la shell MongoDB installata in precedenza nei passaggi seguenti per creare un database, creare raccolte e archiviare documenti. Per altre informazioni sui comandi della shell mongoDB, vedere mongosh.

  1. Aprire un'istanza della shell dei comandi di MongoDB avviando mongosh.exeo eseguendo il comando seguente nella shell dei comandi:

    mongosh
    
  2. Nella shell dei comandi connettersi al database di test predefinito eseguendo:

    use BookStore
    

    Se non esiste già, viene creato un database denominato BookStore . Se il database esiste, la connessione viene aperta per le transazioni.

  3. Creare una raccolta Books tramite il comando seguente:

    db.createCollection('Books')
    

    Viene visualizzato il risultato seguente:

    { "ok" : 1 }
    
  4. Definire uno schema per la raccolta Books e inserire due documenti usando il comando seguente:

    db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
    

    Viene visualizzato un risultato simile al seguente:

    {
        "acknowledged" : true,
        "insertedIds" : [
            ObjectId("61a6058e6c43f32854e51f51"),
            ObjectId("61a6058e6c43f32854e51f52")
         ]
     }
    

    Nota

    I ObjectIdvalori visualizzati nel risultato precedente non corrispondono a quelli visualizzati nella shell dei comandi.

  5. Visualizzare i documenti nel database usando il comando seguente:

    db.Books.find().pretty()
    

    Viene visualizzato un risultato simile al seguente:

    {
         "_id" : ObjectId("61a6058e6c43f32854e51f51"),
         "Name" : "Design Patterns",
         "Price" : 54.93,
         "Category" : "Computers",
         "Author" : "Ralph Johnson"
     }
     {
         "_id" : ObjectId("61a6058e6c43f32854e51f52"),
         "Name" : "Clean Code",
         "Price" : 43.15,
         "Category" : "Computers",
         "Author" : "Robert C. Martin"
     }
    

    Lo schema aggiunge una proprietà _id generata automaticamente di tipo ObjectId per ogni documento.

Creare il progetto per l'API Web ASP.NET Core

  1. Passare a File>Nuovo>Progetto.

  2. Selezionare il tipo di progetto API Web core ASP.NET e selezionare Avanti.

  3. Assegnare al progetto il nome BookStoreApi e selezionare Avanti.

  4. Selezionare il framework .NET 6.0 (supporto a lungo termine) e selezionare Crea.

  5. Nella finestra Console di Gestione pacchetti passare alla radice del progetto. Eseguire il comando seguente per installare il driver .NET per MongoDB:

    Install-Package MongoDB.Driver
    

Aggiungere un modello di entità

  1. Aggiungere una directory Models alla radice del progetto.

  2. Aggiungere una classe Book alla directory Models con il codice seguente:

    using MongoDB.Bson;
    using MongoDB.Bson.Serialization.Attributes;
    
    namespace BookStoreApi.Models;
    
    public class Book
    {
        [BsonId]
        [BsonRepresentation(BsonType.ObjectId)]
        public string? Id { get; set; }
    
        [BsonElement("Name")]
        public string BookName { get; set; } = null!;
    
        public decimal Price { get; set; }
    
        public string Category { get; set; } = null!;
    
        public string Author { get; set; } = null!;
    }
    

    Nella classe precedente la Id proprietà è:

    • Obbligatorio per eseguire il mapping dell'oggetto Common Language Runtime (CLR) alla collezione MongoDB.
    • Annotato con [BsonId] per impostare questa proprietà come chiave primaria del documento.
    • Annotato con [BsonRepresentation(BsonType.ObjectId)] per consentire il passaggio del parametro come tipo string invece di una struttura ObjectId . Mongo gestisce la conversione da string a ObjectId.

    La BookName proprietà viene annotata con l'attributo [BsonElement] . Il valore dell'attributo Name rappresenta il nome della proprietà nella raccolta MongoDB.

Aggiungere un modello di configurazione

  1. Aggiungere i valori di configurazione del database seguenti a appsettings.json:

    {
        "BookStoreDatabase": {
            "ConnectionString": "mongodb://localhost:27017",
            "DatabaseName": "BookStore",
            "BooksCollectionName": "Books"
        },
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft.AspNetCore": "Warning"
            }
        },
        "AllowedHosts": "*"
    }
    
  2. Aggiungere una classe BookStoreDatabaseSettings alla directory Models con il codice seguente:

    namespace BookStoreApi.Models;
    
    public class BookStoreDatabaseSettings
    {
        public string ConnectionString { get; set; } = null!;
    
        public string DatabaseName { get; set; } = null!;
    
        public string BooksCollectionName { get; set; } = null!;
    }
    

    La classe precedente BookStoreDatabaseSettings viene usata per archiviare i appsettings.json valori delle proprietà del BookStoreDatabase file. I nomi delle proprietà JSON e C# sono identici per semplificare il processo di mapping.

  3. Aggiungere il codice evidenziato seguente a Program.cs:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    

    Nel codice precedente, l'istanza di configurazione a cui viene associata la sezione appsettings.json del file BookStoreDatabase viene registrata nel contenitore di Iniezione delle dipendenze. Ad esempio, la BookStoreDatabaseSettings proprietà dell'oggetto ConnectionString viene popolata con la BookStoreDatabase:ConnectionString proprietà in appsettings.json.

  4. Aggiungere il codice seguente all'inizio di Program.cs per risolvere il BookStoreDatabaseSettings riferimento:

    using BookStoreApi.Models;
    

Aggiungere un servizio di operazioni CRUD

  1. Aggiungere una directory Services alla radice del progetto.

  2. Aggiungere una classe BooksService alla directory Services con il codice seguente:

    using BookStoreApi.Models;
    using Microsoft.Extensions.Options;
    using MongoDB.Driver;
    
    namespace BookStoreApi.Services;
    
    public class BooksService
    {
        private readonly IMongoCollection<Book> _booksCollection;
    
        public BooksService(
            IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
        {
            var mongoClient = new MongoClient(
                bookStoreDatabaseSettings.Value.ConnectionString);
    
            var mongoDatabase = mongoClient.GetDatabase(
                bookStoreDatabaseSettings.Value.DatabaseName);
    
            _booksCollection = mongoDatabase.GetCollection<Book>(
                bookStoreDatabaseSettings.Value.BooksCollectionName);
        }
    
        public async Task<List<Book>> GetAsync() =>
            await _booksCollection.Find(_ => true).ToListAsync();
    
        public async Task<Book?> GetAsync(string id) =>
            await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync();
    
        public async Task CreateAsync(Book newBook) =>
            await _booksCollection.InsertOneAsync(newBook);
    
        public async Task UpdateAsync(string id, Book updatedBook) =>
            await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook);
    
        public async Task RemoveAsync(string id) =>
            await _booksCollection.DeleteOneAsync(x => x.Id == id);
    }
    

    Nel codice precedente, un'istanza BookStoreDatabaseSettings viene recuperata tramite l'iniezione delle dipendenze via iniezione nel costruttore. Questa tecnica consente di accedere ai valori di appsettings.json configurazione aggiunti nella sezione Aggiungere un modello di configurazione.

  3. Aggiungere il codice evidenziato seguente a Program.cs:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    
    builder.Services.AddSingleton<BooksService>();
    

    Nel codice precedente, la classe BooksService è registrata con DI per supportare l'inserimento di costruttori nelle classi che la consumano. La durata del servizio singleton è più appropriata perché BooksService assume una dipendenza diretta a MongoClient. In base alle linee guida per il riutilizzo di Mongo Client ufficiali, MongoClient deve essere registrato nell'inserimento di dipendenze con un ciclo di vita del servizio singleton.

  4. Aggiungere il codice seguente all'inizio di Program.cs per risolvere il BooksService riferimento:

    using BookStoreApi.Services;
    

La BooksService classe usa i membri seguenti MongoDB.Driver per eseguire operazioni CRUD sul database:

  • MongoClient: legge l'istanza del server per l'esecuzione di operazioni di database. Al costruttore di questa classe viene passata la stringa di connessione MongoDB:

    public BooksService(
        IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings)
    {
        var mongoClient = new MongoClient(
            bookStoreDatabaseSettings.Value.ConnectionString);
    
        var mongoDatabase = mongoClient.GetDatabase(
            bookStoreDatabaseSettings.Value.DatabaseName);
    
        _booksCollection = mongoDatabase.GetCollection<Book>(
            bookStoreDatabaseSettings.Value.BooksCollectionName);
    }
    
  • IMongoDatabase: rappresenta il database Mongo per l'esecuzione delle operazioni. Questa esercitazione usa il metodo getCollection<TDocument>(collection) generico sull'interfaccia per ottenere l'accesso ai dati in una raccolta specifica. Eseguire operazioni CRUD sulla raccolta dopo che questo metodo viene chiamato. Nella chiamata del metodo GetCollection<TDocument>(collection):

    • collection rappresenta il nome della raccolta.
    • TDocument rappresenta il tipo di oggetto CLR archiviato nella raccolta.

GetCollection<TDocument>(collection) restituisce un oggetto MongoCollection che rappresenta la raccolta. In questa esercitazione, vengono richiamati i metodi seguenti sulla raccolta:

  • DeleteOneAsync: elimina un singolo documento corrispondente ai criteri di ricerca specificati.
  • Trova<TDocument>: restituisce tutti i documenti nella raccolta che corrispondono ai criteri di ricerca specificati.
  • InsertOneAsync: inserisce l'oggetto fornito come nuovo documento nell'insieme.
  • ReplaceOneAsync: sostituisce il singolo documento corrispondente ai criteri di ricerca specificati con l'oggetto specificato.

Aggiungere un controller

Aggiungere una classe BooksController alla directory Controllers con il codice seguente:

using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;

namespace BookStoreApi.Controllers;

[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
    private readonly BooksService _booksService;

    public BooksController(BooksService booksService) =>
        _booksService = booksService;

    [HttpGet]
    public async Task<List<Book>> Get() =>
        await _booksService.GetAsync();

    [HttpGet("{id:length(24)}")]
    public async Task<ActionResult<Book>> Get(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        return book;
    }

    [HttpPost]
    public async Task<IActionResult> Post(Book newBook)
    {
        await _booksService.CreateAsync(newBook);

        return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
    }

    [HttpPut("{id:length(24)}")]
    public async Task<IActionResult> Update(string id, Book updatedBook)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        updatedBook.Id = book.Id;

        await _booksService.UpdateAsync(id, updatedBook);

        return NoContent();
    }

    [HttpDelete("{id:length(24)}")]
    public async Task<IActionResult> Delete(string id)
    {
        var book = await _booksService.GetAsync(id);

        if (book is null)
        {
            return NotFound();
        }

        await _booksService.RemoveAsync(id);

        return NoContent();
    }
}

Il controller dell'API Web precedente:

  • Usa la BooksService classe per eseguire operazioni CRUD.
  • Contiene metodi di azione per supportare le richieste HTTP GET, POST, PUT e DELETE.
  • Chiama CreatedAtAction nel metodo dell'azione Create per restituire una risposta HTTP 201. Il codice di stato 201 è la risposta standard per un metodo HTTP POST che crea una nuova risorsa nel server. CreatedAtAction aggiunge anche un'intestazione Location alla risposta. L'intestazione Location specifica l'URI del libro appena creato.

Testare l'API Web

  1. Compilare ed eseguire l'app.

  2. Passare a https://localhost:<port>/api/books, dove <port> è il numero di porta assegnato automaticamente per l'app, per testare il metodo di azione senza Get parametri del controller. Viene visualizzata una risposta JSON simile alla seguente:

    [
      {
        "id": "61a6058e6c43f32854e51f51",
        "bookName": "Design Patterns",
        "price": 54.93,
        "category": "Computers",
        "author": "Ralph Johnson"
      },
      {
        "id": "61a6058e6c43f32854e51f52",
        "bookName": "Clean Code",
        "price": 43.15,
        "category": "Computers",
        "author": "Robert C. Martin"
      }
    ]
    
  3. Passare a https://localhost:<port>/api/books/{id here} per testare il metodo azione sovraccaricato Get del controller. Viene visualizzata una risposta JSON simile alla seguente:

    {
      "id": "61a6058e6c43f32854e51f52",
      "bookName": "Clean Code",
      "price": 43.15,
      "category": "Computers",
      "author": "Robert C. Martin"
    }
    

Configurare le opzioni di serializzazione JSON

Esistono due dettagli da modificare per le risposte JSON restituite nella sezione Testare l'API Web:

  • La notazione a cammello predefinita per i nomi di proprietà deve essere modificata in modo da adottare la convenzione Pascal dei nomi di proprietà dell'oggetto CLR.
  • La proprietà bookName deve essere restituita come Name.

Per soddisfare i requisiti precedenti, apportare le modifiche seguenti:

  1. In Program.cs concatenare il codice evidenziato seguente alla chiamata del metodo AddControllers:

    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    builder.Services.Configure<BookStoreDatabaseSettings>(
        builder.Configuration.GetSection("BookStoreDatabase"));
    
    builder.Services.AddSingleton<BooksService>();
    
    builder.Services.AddControllers()
        .AddJsonOptions(
            options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
    

    Con la modifica precedente, i nomi delle proprietà nella risposta JSON serializzata dell'API Web corrispondono ai nomi di proprietà corrispondenti nel tipo di oggetto CLR. Ad esempio, la Book proprietà della Author classe serializza come Author anziché author.

  2. In Models/Book.csannotare la BookName proprietà con l'attributo [JsonPropertyName] :

    [BsonElement("Name")]
    [JsonPropertyName("Name")]
    public string BookName { get; set; } = null!;
    

    Il valore [JsonPropertyName] dell'attributo Name rappresenta il nome della proprietà nella risposta JSON serializzata dell'API Web.

  3. Aggiungere il codice seguente all'inizio di Models/Book.cs per risolvere il riferimento all'attributo [JsonProperty] :

    using System.Text.Json.Serialization;
    
  4. Ripetere i passaggi definiti nella sezione Testare l'API Web. Si noti la differenza nei nomi di proprietà JSON.

Aggiungere il supporto per l'autenticazione a un'API Web

ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web ASP.NET Core. Per proteggere le API web e le applicazioni a pagina singola, usare una delle opzioni seguenti:

Duende Identity Server è un framework OpenID Connect e OAuth 2.0 per ASP.NET Core. Duende Identity Server abilita le funzionalità di sicurezza seguenti:

  • Autenticazione come servizio (AaaS)
  • Single Sign-On/off (SSO) su più tipi di applicazione
  • Controllo di accesso per le API
  • Gateway federativo

Importante

Duende Software potrebbe richiedere il pagamento di una tariffa di licenza per l'uso in produzione di Duende Identity Server. Per altre informazioni, vedere Eseguire la migrazione da ASP.NET Core 5.0 a 6.0.

Per altre informazioni, vedere la documentazione di Duende Server (sito Web duende Identity Software).

Risorse aggiuntive

Questa esercitazione crea un'API Web che esegue operazioni Create, Read, Update e Delete (CRUD) in un database NoSQL mongoDB .

In questa esercitazione apprenderai a:

  • Configurare MongoDB
  • Creare un database MongoDB
  • Definire una raccolta e uno schema MongoDB
  • Eseguire operazioni CRUD di MongoDB da un'API Web
  • Personalizzare la serializzazione JSON

Visualizzare o scaricare il codice di esempio (procedura per il download)

Prerequisiti

Configurare MongoDB

Se si usa Windows, MongoDB è installato in C:\Programmi\MongoDB per impostazione predefinita. Aggiungere C:\Programmi\MongoDB\Server\<version_number>\bin alla Path variabile di ambiente. Questa modifica consente l'accesso MongoDB da qualsiasi posizione nel computer di sviluppo.

Usare la shell mongo nelle procedure seguenti per creare un database, creare le raccolte e archiviare i documenti. Per altre informazioni sui comandi della shell mongo, vedere Working with the mongo Shell (Utilizzo della shell mongo).

  1. Scegliere una directory nel computer di sviluppo per archiviare i dati. Ad esempio, C:\BooksData in Windows. Crea la directory se non esiste. La shell mongo non consente di creare nuove directory.

  2. Aprire una shell dei comandi. Eseguire il comando seguente per connettersi a MongoDB sulla porta predefinita 27017. Ricordare di sostituire <data_directory_path> con la directory scelta nel passaggio precedente.

    mongod --dbpath <data_directory_path>
    
  3. Aprire un'altra istanza della shell dei comandi. Connettersi al database di test predefinito eseguendo il comando seguente:

    mongo
    
  4. Eseguire il comando seguente in un prompt dei comandi:

    use BookstoreDb
    

    Se non esiste già, viene creato un database denominato BookstoreDb . Se il database esiste, la connessione viene aperta per le transazioni.

  5. Creare una raccolta Books tramite il comando seguente:

    db.createCollection('Books')
    

    Viene visualizzato il risultato seguente:

    { "ok" : 1 }
    
  6. Definire uno schema per la raccolta Books e inserire due documenti usando il comando seguente:

    db.Books.insertMany([{'Name':'Design Patterns','Price':54.93,'Category':'Computers','Author':'Ralph Johnson'}, {'Name':'Clean Code','Price':43.15,'Category':'Computers','Author':'Robert C. Martin'}])
    

    Viene visualizzato il risultato seguente:

    {
      "acknowledged" : true,
      "insertedIds" : [
        ObjectId("5bfd996f7b8e48dc15ff215d"),
        ObjectId("5bfd996f7b8e48dc15ff215e")
      ]
    }
    

    Nota

    Gli ID mostrati in questo articolo non corrisponderanno agli ID quando si esegue questo esempio.

  7. Visualizzare i documenti nel database usando il comando seguente:

    db.Books.find({}).pretty()
    

    Viene visualizzato il risultato seguente:

    {
      "_id" : ObjectId("5bfd996f7b8e48dc15ff215d"),
      "Name" : "Design Patterns",
      "Price" : 54.93,
      "Category" : "Computers",
      "Author" : "Ralph Johnson"
    }
    {
      "_id" : ObjectId("5bfd996f7b8e48dc15ff215e"),
      "Name" : "Clean Code",
      "Price" : 43.15,
      "Category" : "Computers",
      "Author" : "Robert C. Martin"
    }
    

    Lo schema aggiunge una proprietà _id generata automaticamente di tipo ObjectId per ogni documento.

Il database è pronto. È possibile iniziare a creare l'API Web ASP.NET Core.

Creare il progetto per l'API Web ASP.NET Core

  1. Vai a File>Nuovo>Progetto.

  2. Selezionare il tipo di progetto Applicazione Web ASP.NET Core e selezionare Avanti.

  3. Assegnare al progetto il nome BooksApi e selezionare Crea.

  4. Selezionare il framework di destinazione .NET Core e ASP.NET Core 3.0. Selezionare il modello di progetto API e scegliere Crea.

  5. Visitare la raccolta NuGet: MongoDB.Driver per determinare la versione stabile più recente del driver .NET per MongoDB. Nella finestra Console di Gestione pacchetti passare alla radice del progetto. Eseguire il comando seguente per installare il driver .NET per MongoDB:

    Install-Package MongoDB.Driver -Version {VERSION}
    

Aggiungere un modello di entità

  1. Aggiungere una directory Models alla radice del progetto.

  2. Aggiungere una classe Book alla directory Models con il codice seguente:

    using MongoDB.Bson;
    using MongoDB.Bson.Serialization.Attributes;
    
    namespace BooksApi.Models
    {
        public class Book
        {
            [BsonId]
            [BsonRepresentation(BsonType.ObjectId)]
            public string Id { get; set; }
    
            [BsonElement("Name")]
            public string BookName { get; set; }
    
            public decimal Price { get; set; }
    
            public string Category { get; set; }
    
            public string Author { get; set; }
        }
    }
    

    Nella classe precedente la Id proprietà è:

    • Obbligatorio per eseguire il mapping dell'oggetto Common Language Runtime (CLR) alla collezione MongoDB.
    • Annotato con [BsonId] per impostare questa proprietà come chiave primaria del documento.
    • Annotato con [BsonRepresentation(BsonType.ObjectId)] per consentire il passaggio del parametro come tipo string invece di una struttura ObjectId . Mongo gestisce la conversione da string a ObjectId.

    La BookName proprietà viene annotata con l'attributo [BsonElement] . Il valore dell'attributo Name rappresenta il nome della proprietà nella raccolta MongoDB.

Aggiungere un modello di configurazione

  1. Aggiungere i valori di configurazione del database seguenti a appsettings.json:

    {
      "BookstoreDatabaseSettings": {
        "BooksCollectionName": "Books",
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookstoreDb"
      },
      "Logging": {
        "IncludeScopes": false,
        "Debug": {
          "LogLevel": {
            "Default": "Warning"
          }
        },
        "Console": {
          "LogLevel": {
            "Default": "Warning"
          }
        }
      }
    }
    
  2. Aggiungere un BookstoreDatabaseSettings.cs file alla directory Models con il codice seguente:

    namespace BooksApi.Models
    {
        public class BookstoreDatabaseSettings : IBookstoreDatabaseSettings
        {
            public string BooksCollectionName { get; set; }
            public string ConnectionString { get; set; }
            public string DatabaseName { get; set; }
        }
    
        public interface IBookstoreDatabaseSettings
        {
            string BooksCollectionName { get; set; }
            string ConnectionString { get; set; }
            string DatabaseName { get; set; }
        }
    }
    

    La classe precedente BookstoreDatabaseSettings viene usata per archiviare i appsettings.json valori delle proprietà del BookstoreDatabaseSettings file. I nomi delle proprietà JSON e C# sono identici per semplificare il processo di mapping.

  3. Aggiungere il codice evidenziato seguente a Startup.ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        // requires using Microsoft.Extensions.Options
        services.Configure<BookstoreDatabaseSettings>(
            Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
    
        services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
            sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
    
        services.AddControllers();
    }
    

    Nel codice precedente:

    • L'istanza di configurazione a cui la sezione del file appsettings.json viene associata è registrata nel contenitore di iniezione delle dipendenze. Ad esempio, la proprietà `BookstoreDatabaseSettings` di un oggetto `ConnectionString` viene popolata con la proprietà `BookstoreDatabaseSettings:ConnectionString` in `appsettings.json`.
    • L'interfaccia IBookstoreDatabaseSettings è registrata in DI con un ciclo di vita del servizio singleton. Quando avviene l'inserimento, l'istanza dell'interfaccia restituisce un oggetto BookstoreDatabaseSettings.
  4. Aggiungere il codice seguente all'inizio di Startup.cs per risolvere i riferimenti BookstoreDatabaseSettings e IBookstoreDatabaseSettings.

    using BooksApi.Models;
    

Aggiungere un servizio di operazioni CRUD

  1. Aggiungere una directory Services alla radice del progetto.

  2. Aggiungere una classe BookService alla directory Services con il codice seguente:

    using BooksApi.Models;
    using MongoDB.Driver;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace BooksApi.Services
    {
        public class BookService
        {
            private readonly IMongoCollection<Book> _books;
    
            public BookService(IBookstoreDatabaseSettings settings)
            {
                var client = new MongoClient(settings.ConnectionString);
                var database = client.GetDatabase(settings.DatabaseName);
    
                _books = database.GetCollection<Book>(settings.BooksCollectionName);
            }
    
            public List<Book> Get() =>
                _books.Find(book => true).ToList();
    
            public Book Get(string id) =>
                _books.Find<Book>(book => book.Id == id).FirstOrDefault();
    
            public Book Create(Book book)
            {
                _books.InsertOne(book);
                return book;
            }
    
            public void Update(string id, Book bookIn) =>
                _books.ReplaceOne(book => book.Id == id, bookIn);
    
            public void Remove(Book bookIn) =>
                _books.DeleteOne(book => book.Id == bookIn.Id);
    
            public void Remove(string id) => 
                _books.DeleteOne(book => book.Id == id);
        }
    }
    

    Nel codice precedente un'istanza di IBookstoreDatabaseSettings viene recuperata dall'inserimento di dipendenze tramite l'inserimento del costruttore. Questa tecnica consente di accedere ai valori di appsettings.json configurazione aggiunti nella sezione Aggiungere un modello di configurazione.

  3. Aggiungere il codice evidenziato seguente a Startup.ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<BookstoreDatabaseSettings>(
            Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
    
        services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
            sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
    
        services.AddSingleton<BookService>();
    
        services.AddControllers();
    }
    

    Nel codice precedente la classe BookService è registrata con l'inserimento di dipendenze per supportare l'inserimento del costruttore nelle classi che la utilizzano. La durata del servizio singleton è più appropriata perché BookService assume una dipendenza diretta a MongoClient. In base alle linee guida per il riutilizzo di Mongo Client ufficiali, MongoClient deve essere registrato nell'inserimento di dipendenze con un ciclo di vita del servizio singleton.

  4. Aggiungere il codice seguente all'inizio di Startup.cs per risolvere il BookService riferimento:

    using BooksApi.Services;
    

La BookService classe usa i membri seguenti MongoDB.Driver per eseguire operazioni CRUD sul database:

  • MongoClient: legge l'istanza del server per l'esecuzione di operazioni di database. Al costruttore di questa classe viene passata la stringa di connessione MongoDB:

    public BookService(IBookstoreDatabaseSettings settings)
    {
        var client = new MongoClient(settings.ConnectionString);
        var database = client.GetDatabase(settings.DatabaseName);
    
        _books = database.GetCollection<Book>(settings.BooksCollectionName);
    }
    
  • IMongoDatabase: rappresenta il database Mongo per l'esecuzione delle operazioni. Questa esercitazione usa il metodo getCollection<TDocument>(collection) generico sull'interfaccia per ottenere l'accesso ai dati in una raccolta specifica. Eseguire operazioni CRUD sulla raccolta dopo che questo metodo viene chiamato. Nella chiamata del metodo GetCollection<TDocument>(collection):

    • collection rappresenta il nome della raccolta.
    • TDocument rappresenta il tipo di oggetto CLR archiviato nella raccolta.

GetCollection<TDocument>(collection) restituisce un oggetto MongoCollection che rappresenta la raccolta. In questa esercitazione, vengono richiamati i metodi seguenti sulla raccolta:

  • DeleteOne: elimina un singolo documento corrispondente ai criteri di ricerca specificati.
  • Trova<TDocument>: restituisce tutti i documenti nella raccolta che corrispondono ai criteri di ricerca specificati.
  • InsertOne: inserisce l'oggetto fornito come nuovo documento nell'insieme.
  • ReplaceOne: sostituisce il singolo documento corrispondente ai criteri di ricerca specificati con l'oggetto specificato.

Aggiungere un controller

Aggiungere una classe BooksController alla directory Controllers con il codice seguente:

using BooksApi.Models;
using BooksApi.Services;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace BooksApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BooksController : ControllerBase
    {
        private readonly BookService _bookService;

        public BooksController(BookService bookService)
        {
            _bookService = bookService;
        }

        [HttpGet]
        public ActionResult<List<Book>> Get() =>
            _bookService.Get();

        [HttpGet("{id:length(24)}", Name = "GetBook")]
        public ActionResult<Book> Get(string id)
        {
            var book = _bookService.Get(id);

            if (book == null)
            {
                return NotFound();
            }

            return book;
        }

        [HttpPost]
        public ActionResult<Book> Create(Book book)
        {
            _bookService.Create(book);

            return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
        }

        [HttpPut("{id:length(24)}")]
        public IActionResult Update(string id, Book bookIn)
        {
            var book = _bookService.Get(id);

            if (book == null)
            {
                return NotFound();
            }

            _bookService.Update(id, bookIn);

            return NoContent();
        }

        [HttpDelete("{id:length(24)}")]
        public IActionResult Delete(string id)
        {
            var book = _bookService.Get(id);

            if (book == null)
            {
                return NotFound();
            }

            _bookService.Remove(id);

            return NoContent();
        }
    }
}

Il controller dell'API Web precedente:

  • Usa la BookService classe per eseguire operazioni CRUD.
  • Contiene metodi di azione per supportare le richieste HTTP GET, POST, PUT e DELETE.
  • Chiama CreatedAtRoute nel metodo dell'azione Create per restituire una risposta HTTP 201. Il codice di stato 201 è la risposta standard per un metodo HTTP POST che crea una nuova risorsa nel server. CreatedAtRoute aggiunge anche un'intestazione Location alla risposta. L'intestazione Location specifica l'URI del libro appena creato.

Testare l'API Web

  1. Compilare ed eseguire l'app.

  2. Passare a https://localhost:<port>/api/books per testare il metodo azione Get senza parametri del controller. Viene visualizzata la risposta JSON seguente:

    [
      {
        "id":"5bfd996f7b8e48dc15ff215d",
        "bookName":"Design Patterns",
        "price":54.93,
        "category":"Computers",
        "author":"Ralph Johnson"
      },
      {
        "id":"5bfd996f7b8e48dc15ff215e",
        "bookName":"Clean Code",
        "price":43.15,
        "category":"Computers",
        "author":"Robert C. Martin"
      }
    ]
    
  3. Passare a https://localhost:<port>/api/books/{id here} per testare il metodo azione sovraccaricato Get del controller. Viene visualizzata la risposta JSON seguente:

    {
      "id":"{ID}",
      "bookName":"Clean Code",
      "price":43.15,
      "category":"Computers",
      "author":"Robert C. Martin"
    }
    

Configurare le opzioni di serializzazione JSON

Esistono due dettagli da modificare per le risposte JSON restituite nella sezione Testare l'API Web:

  • La notazione a cammello predefinita per i nomi di proprietà deve essere modificata in modo da adottare la convenzione Pascal dei nomi di proprietà dell'oggetto CLR.
  • La proprietà bookName deve essere restituita come Name.

Per soddisfare i requisiti precedenti, apportare le modifiche seguenti:

  1. Json.NET è stato rimosso dal framework condiviso di ASP.NET. Aggiungere un riferimento al pacchetto a Microsoft.AspNetCore.Mvc.NewtonsoftJson.

  2. In Startup.ConfigureServices concatenare il codice evidenziato seguente alla chiamata del metodo AddControllers:

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<BookstoreDatabaseSettings>(
            Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
    
        services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
            sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
    
        services.AddSingleton<BookService>();
    
        services.AddControllers()
            .AddNewtonsoftJson(options => options.UseMemberCasing());
    }
    

    Con la modifica precedente, i nomi delle proprietà nella risposta JSON serializzata dell'API Web corrispondono ai nomi di proprietà corrispondenti nel tipo di oggetto CLR. Ad esempio, la proprietà Book della classe Author viene serializzata come Author.

  3. In Models/Book.csannotare la BookName proprietà con l'attributo seguente [JsonProperty] :

    [BsonElement("Name")]
    [JsonProperty("Name")]
    public string BookName { get; set; }
    

    Il valore [JsonProperty] dell'attributo Name rappresenta il nome della proprietà nella risposta JSON serializzata dell'API Web.

  4. Aggiungere il codice seguente all'inizio di Models/Book.cs per risolvere il riferimento all'attributo [JsonProperty] :

    using Newtonsoft.Json;
    
  5. Ripetere i passaggi definiti nella sezione Testare l'API Web. Si noti la differenza nei nomi di proprietà JSON.

Aggiungere il supporto per l'autenticazione a un'API Web

ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web ASP.NET Core. Per proteggere le API web e le applicazioni a pagina singola, usare una delle opzioni seguenti:

Duende IdentityServer è un framework OpenID Connect e OAuth 2.0 per ASP.NET Core. Duende IdentityServer abilita le funzionalità di sicurezza seguenti:

  • Autenticazione come servizio (AaaS)
  • Single Sign-On/off (SSO) su più tipi di applicazione
  • Controllo di accesso per le API
  • Gateway federativo

Per altre informazioni, vedere Panoramica di Duende IdentityServer.

Per altre informazioni su altri provider di autenticazione, vedere Opzioni di autenticazione del sistema operativo della community per ASP.NET Core

Passaggi successivi

Per altre informazioni sulla creazione di API Web ASP.NET Core, vedere le risorse seguenti: