Esercitazione: Creare un'API Web con ASP.NET Core
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 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 8 di questo articolo.
Di Rick Anderson e Kirk Larkin
Questa esercitazione illustra le nozioni di base per la creazione di un'API Web basata su controller che usa un database. Un altro approccio alla creazione di API in ASP.NET Core consiste nel creare API minime. Per informazioni sulla scelta tra API minime e API basate su controller, vedere Panoramica delle API. Per un'esercitazione sulla creazione di un'API minima, vedere Esercitazione: Creare un'API minima con ASP.NET Core.
Panoramica
Questa esercitazione consente di creare l'API seguente:
API | Descrizione | Testo della richiesta | Corpo della risposta |
---|---|---|---|
GET /api/todoitems |
Ottiene tutti gli elementi attività | None | Matrice di elementi attività |
GET /api/todoitems/{id} |
Ottiene un elemento in base all'ID | None | Elemento attività |
POST /api/todoitems |
Aggiunge un nuovo elemento | Elemento attività | Elemento attività |
PUT /api/todoitems/{id} |
Aggiorna un elemento esistente | Elemento attività | None |
DELETE /api/todoitems/{id} |
Elimina un elemento | None | None |
Il diagramma seguente visualizza la struttura dell'app.
Prerequisiti
Visual Studio 2022 con il carico di lavoro Sviluppo ASP.NET e Web.
Creare un progetto Web
- Scegliere Nuovo>Progetto dal menu File.
- Immettere l'API Web nella casella di ricerca.
- Selezionare il modello API Web ASP.NET Core e selezionare Avanti.
- Nella finestra di dialogo Configura il nuovo progetto assegnare al progetto il nome TodoApi e selezionare Avanti.
- Nella finestra di dialogo Informazioni aggiuntive:
- Verificare che Framework sia .NET 8.0 (supporto a lungo termine).
- Verificare che la casella di controllo Usa controller (deselezionare per usare le API minime) sia selezionata.
- Verificare che la casella di controllo Abilita supporto OpenAPI sia selezionata.
- Seleziona Crea.
Aggiungere un pacchetto NuGet
È necessario aggiungere un pacchetto NuGet per supportare il database usato in questa esercitazione.
- Scegliere NuGet Gestione pacchetti > Gestisci pacchetti NuGet per la soluzione dal menu Strumenti.
- Selezionare la scheda Sfoglia.
- Immettere Microsoft.EntityFrameworkCore.InMemory nella casella di ricerca e quindi selezionare
Microsoft.EntityFrameworkCore.InMemory
. - Selezionare la casella di controllo Progetto nel riquadro destro e quindi selezionare Installa.
Nota
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.
Testare il progetto
Il modello di progetto crea un'API WeatherForecast
con supporto per Swagger.
Premere CTRL+F5 per l'esecuzione senza il debugger.
Visual Studio visualizza la finestra di dialogo seguente quando un progetto non è ancora configurato per l'uso di SSL:
Selezionare Sì se si considera attendibile il certificato SSL di IIS Express.
Verrà visualizzata la finestra di dialogo seguente:
Selezionare Sì se si accetta di considerare attendibile il certificato di sviluppo.
Per informazioni sull'attendibilità del browser Firefox, vedere Firefox edizione Standard C_ERROR_INADEQUATE_KEY_USAGE errore del certificato.
Visual Studio avvia il browser predefinito e passa a https://localhost:<port>/swagger/index.html
, dove <port>
è un numero di porta scelto in modo casuale impostato durante la creazione del progetto.
Viene visualizzata la pagina /swagger/index.html
Swagger. Selezionare GET>Try it out>Execute (Esegui). La pagina visualizza:
- Comando Curl per testare l'API WeatherForecast.
- URL per testare l'API WeatherForecast.
- Codice di risposta, corpo e intestazioni.
- Casella di riepilogo a discesa con tipi di supporti e il valore e lo schema di esempio.
Se la pagina Swagger non viene visualizzata, vedere questo problema di GitHub.
Swagger viene usato per generare una documentazione utile e pagine della Guida per le API Web. Questa esercitazione usa Swagger per testare l'app. Per altre informazioni su Swagger, vedere ASP.NET documentazione dell'API Web core con Swagger/OpenAPI.
Copiare e incollare l'URL della richiesta nel browser:https://localhost:<port>/weatherforecast
JSON simile all'esempio seguente viene restituito:
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Aggiungere una classe modello
Un modello è un set di classi che rappresentano i dati gestiti dall'app. Il modello per questa app è la TodoItem
classe .
- In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto. Selezionare Aggiungi>Nuova cartella. Denominare la cartella
Models
. - Fare clic con il pulsante destro del mouse sulla
Models
cartella e scegliere Aggiungi>classe. Assegnare alla classe il nome TodoItem e selezionare Aggiungi. - Sostituire il codice del modello con quanto segue:
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
La proprietà Id
funziona come chiave univoca in un database relazionale.
Le classi di modello possono essere usate in qualsiasi punto del progetto, ma la Models
cartella viene usata per convenzione.
Aggiungere un contesto di database
Il contesto di database è la classe principale che coordina le funzionalità di Entity Framework per un modello di dati. Questa classe viene creata mediante derivazione dalla classe Microsoft.EntityFrameworkCore.DbContext.
- Fare clic con il pulsante destro del mouse sulla
Models
cartella e scegliere Aggiungi>classe. Assegnare alla classe il nome TodoContext e fare clic su Aggiungi.
Immetti il codice seguente:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
Registrare il contesto del database
In ASP.NET Core i servizi come il contesto del database devono essere registrati con il contenitore di inserimento delle dipendenze. Il contenitore rende disponibile il servizio ai controller.
Eseguire l'aggiornamento Program.cs
con il codice evidenziato seguente:
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Il codice precedente:
- Aggiunge
using
direttive. - Aggiunge il contesto del database al contenitore di inserimento delle dipendenze.
- Specifica che il contesto del database userà un database in memoria.
Eseguire lo scaffolding di un controller
Fare clic con il pulsante destro del mouse sulla
Controllers
cartella.Selezionare Aggiungi>New Scaffolded Item.
Selezionare Controller API con azioni, che usa Entity Framework e quindi selezionare Aggiungi.
Nella finestra di dialogo Add API Controller with actions, using Entity Framework (Aggiungi controller API con azioni, che usa Entity Framework):
- Selezionare TodoItem (TodoApi.Models) nella classe Model.
- Selezionare TodoContext (TodoApi.Models) nella classe Contesto dati.
- Selezionare Aggiungi.
Se l'operazione di scaffolding non riesce, selezionare Aggiungi per provare a eseguire lo scaffolding una seconda volta.
Il codice generato:
- Contrassegna la classe con l'attributo
[ApiController]
. L'attributo indica che il controller risponde alle richieste di API Web. Per informazioni sui comportamenti specifici che l'attributo abilita, vedere Creare API Web con ASP.NET Core. - Usa l'inserimento delle dipendenze per inserire il contesto del database (
TodoContext
) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.
I modelli ASP.NET Core per:
- I controller con visualizzazioni includono
[action]
nel modello di route. - I controller API non includono
[action]
nel modello di route.
Quando il [action]
token non è incluso nel modello di route, il nome dell'azione (nome del metodo) non è incluso nell'endpoint. Ovvero, il nome del metodo associato dell'azione non viene usato nella route corrispondente.
Aggiornare il metodo di creazione PostTodoItem
Aggiornare l'istruzione return in PostTodoItem
per usare l'operatore nameof :
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("PostTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(PostTodoItem), new { id = todoItem.Id }, todoItem);
}
Il codice precedente è un HTTP POST
metodo, come indicato dall'attributo [HttpPost]
. Il metodo ottiene il valore di TodoItem
dal corpo della richiesta HTTP.
Per altre informazioni, vedere Routing con attributi Http[verb].
Il metodo CreatedAtAction:
- Restituisce un codice di stato HTTP 201 se ha esito positivo.
HTTP 201
è la risposta standard per unHTTP POST
metodo che crea una nuova risorsa nel server. - Aggiunge un'intestazione Location alla risposta. L'intestazione
Location
specifica l'URI dell'elemento attività appena creato. Per altre informazioni, vedere 10.2.2 201 Created. - Fa riferimento all'azione
PostTodoItem
per creare l'URI dell'intestazioneLocation
. La parola chiavenameof
C# viene usata per evitare di impostare il nome dell'azione come hardcoded nella chiamata aCreatedAtAction
.
Test PostTodoItem
Premere CTRL+F5 per eseguire l'app.
Nella finestra del browser Swagger selezionare POST /api/TodoItems e quindi selezionare Prova.
Nella finestra Di input del corpo della richiesta aggiornare ONJS. ad esempio:
{ "name": "walk dog", "isComplete": true }
Selezionare Esegui
Testare l'URI dell'intestazione della posizione
Nell'articolo POST precedente, l'interfaccia utente di Swagger mostra l'intestazione della posizione in Intestazioni di risposta. Ad esempio: location: https://localhost:7260/api/TodoItems/1
. L'intestazione della posizione mostra l'URI della risorsa creata.
Per testare l'intestazione della posizione:
Nella finestra del browser Swagger selezionare GET /api/TodoItems/{id}, quindi selezionare Prova.
Immettere
1
nellaid
casella di input e quindi selezionare Esegui.
Esaminare i metodi GET
Vengono implementati due endpoint GET:
GET /api/todoitems
GET /api/todoitems/{id}
La sezione precedente ha mostrato un esempio della /api/todoitems/{id}
route.
Seguire le istruzioni POST per aggiungere un altro elemento todo e quindi testare la /api/todoitems
route usando Swagger.
Questa app usa un database in memoria. Se l'app viene arrestata e avviata, la richiesta GET precedente non restituisce dati. Se non vengono restituiti dati, eseguire POST per pubblicare i dati nell'app.
Routing e percorsi di URL
L'attributo [HttpGet]
indica un metodo che risponde a una HTTP GET
richiesta. Il percorso dell'URL per ogni metodo viene costruito nel modo seguente:
Iniziare con la stringa di modello nell'attributo
Route
del controller:[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
Sostituire
[controller]
con il nome del controller, ovvero, per convenzione, il nome della classe controller meno il suffisso "Controller". In questo esempio il nome della classe controller è TodoItemsController, quindi il nome del controller è "TodoItems". Il routing ASP.NET Core non fa distinzione tra maiuscole e minuscole.Se l'attributo
[HttpGet]
ha un modello di route, ad esempio[HttpGet("products")]
, aggiungerlo al percorso. In questo esempio non si usa un modello. Per altre informazioni, vedere Routing con attributi Http[verb].
Nel metodo GetTodoItem
seguente, "{id}"
è una variabile segnaposto per l'identificatore univoco dell'elemento attività. Quando GetTodoItem
viene richiamato, il valore di "{id}"
nell'URL viene fornito al metodo nel relativo id
parametro.
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Valori restituiti
Il tipo restituito GetTodoItems
dei metodi e GetTodoItem
è Il tipo T> ActionResult<. ASP.NET Core serializza automaticamente l'oggetto in JSON e scrive JSON nel corpo del messaggio di risposta. Il codice di risposta per questo tipo restituito è 200 OK, presupponendo che non siano presenti eccezioni non gestite. Le eccezioni non gestite vengono convertite in errori 5xx.
I tipi restituiti ActionResult
possono rappresentare un ampio intervallo di codici di stato HTTP. Ad esempio, GetTodoItem
può restituire due valori di stato diversi:
- Se nessun elemento corrisponde all'ID richiesto, il metodo restituisce un codice di errore di statoNotFound 404.
- In caso contrario, il metodo restituisce 200 con un corpo della JSrisposta ON. La restituzione dei
item
risultati in unaHTTP 200
risposta.
Metodo PutTodoItem
Esaminare il metodo PutTodoItem
:
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
è simile a PostTodoItem
, ad eccezione del fatto che usa HTTP PUT
. La risposta è 204 (No Content). In base alla specifica HTTP, una PUT
richiesta richiede al client di inviare l'intera entità aggiornata, non solo le modifiche. Per supportare gli aggiornamenti parziali, usare HTTP PATCH.
Testare il metodo PutTodoItem
Questo esempio usa un database in memoria che deve essere inizializzato ogni volta che l'app viene avviata. Deve esistere un elemento nel database prima di eseguire una chiamata PUT. Chiamare GET per assicurarsi che nel database sia presente un elemento prima di effettuare una chiamata PUT.
Usando l'interfaccia utente di Swagger, usare il pulsante PUT per aggiornare l'oggetto TodoItem
con ID = 1 e impostarne il nome su "feed fish"
. Si noti che la risposta è HTTP 204 No Content
.
Metodo DeleteTodoItem
Esaminare il metodo DeleteTodoItem
:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
Testare il metodo DeleteTodoItem
Usare l'interfaccia utente di Swagger per eliminare l'oggetto TodoItem
con ID = 1. Si noti che la risposta è HTTP 204 No Content
.
Testare con altri strumenti
Esistono molti altri strumenti che possono essere usati per testare le API Web, ad esempio:
- Esplora endpoint di Visual Studio e file con estensione http
- http-repl
- curl. Swagger usa
curl
e mostra icurl
comandi inviati. - Fiddler
Per altre informazioni, vedi:
- Esercitazione minima sulle API: testare con file .http ed Esplora endpoint
- Installare e testare le API con
http-repl
Impedire l'over-post
Attualmente l'app di esempio espone l'intero TodoItem
oggetto. Le app di produzione limitano in genere i dati di input e restituiti usando un subset del modello. Ci sono diversi motivi alla base di questo, e la sicurezza è una delle principali. Il subset di un modello viene in genere definito DTO (Data Transfer Object), modello di input o modello di visualizzazione. DTO viene usato in questa esercitazione.
Un DTO può essere usato per:
- Impedire l'over-post.
- Nascondere le proprietà che i client non devono visualizzare.
- Omettere alcune proprietà per ridurre le dimensioni del payload.
- Appiattire gli oggetti grafici che contengono oggetti annidati. Gli oggetti grafici appiattiti possono essere più pratici per i client.
Per illustrare l'approccio DTO, aggiornare la TodoItem
classe in modo da includere un campo segreto:
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
}
Il campo segreto deve essere nascosto da questa app, ma un'app amministrativa potrebbe scegliere di esporla.
Verificare che sia possibile pubblicare e ottenere il campo segreto.
Creare un modello DTO:
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Aggiornare per TodoItemsController
usare TodoItemDTO
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
Verificare che non sia possibile pubblicare o ottenere il campo segreto.
Chiamare l'API Web con JavaScript
Vedere Esercitazione: Chiamare un'API Web ASP.NET Core con JavaScript.
Serie di video dell'API Web
Vedere Video: Beginner's Series to: Web APIs (Serie per principianti: API Web).
Modelli di app Web affidabili
Per indicazioni sulla creazione di un'app moderna, affidabile, affidabile, affidabile, testabile, conveniente e scalabile ASP.NET Core, indipendentemente dal fatto che si tratti di un'app esistente o di refactoring di un'app esistente, vedi Modello di app Web Reliable Web for.NETYouTube.
Aggiungere il supporto per l'autenticazione a un'API Web
ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web core ASP.NET. Per proteggere le API Web e i contratti a pagina singola, usare una delle opzioni seguenti:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server è un framework OpenID Connessione 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).
Pubblicare in Azure
Per informazioni sulla distribuzione in Azure, vedere Avvio rapido: Distribuire un'app Web ASP.NET.
Risorse aggiuntive
Visualizzare o scaricare il codice di esempio per questa esercitazione. Vedere come scaricare un esempio.
Per ulteriori informazioni, vedi le seguenti risorse:
- Creare API Web con ASP.NET Core
- Esercitazione: Creare un'API minima con ASP.NET Core
- Documentazione delle API Web ASP.NET Core con Swagger/OpenAPI
- Razor Pagine con Entity Framework Core in ASP.NET Core - Esercitazione 1 di 8
- Routing alle azioni del controller in ASP.NET Core
- Tipi restituiti dall'azione del controller nell'API Web ASP.NET Core
- Distribuire le app ASP.NET Core in Servizio app di Azure
- Ospitare e distribuire ASP.NET Core
- Creare un'API Web con ASP.NET Core
Questa esercitazione illustra le nozioni di base per la creazione di un'API Web basata su controller che usa un database. Un altro approccio alla creazione di API in ASP.NET Core consiste nel creare API minime. Per informazioni sulla scelta tra API minime e API basate su controller, vedere Panoramica delle API. Per un'esercitazione sulla creazione di un'API minima, vedere Esercitazione: Creare un'API minima con ASP.NET Core.
Panoramica
Questa esercitazione consente di creare l'API seguente:
API | Descrizione | Testo della richiesta | Corpo della risposta |
---|---|---|---|
GET /api/todoitems |
Ottiene tutti gli elementi attività | None | Matrice di elementi attività |
GET /api/todoitems/{id} |
Ottiene un elemento in base all'ID | None | Elemento attività |
POST /api/todoitems |
Aggiunge un nuovo elemento | Elemento attività | Elemento attività |
PUT /api/todoitems/{id} |
Aggiorna un elemento esistente | Elemento attività | None |
DELETE /api/todoitems/{id} |
Elimina un elemento | None | None |
Il diagramma seguente visualizza la struttura dell'app.
Prerequisiti
Visual Studio 2022 con il carico di lavoro Sviluppo ASP.NET e Web.
Creare un progetto Web
- Scegliere Nuovo>Progetto dal menu File.
- Immettere l'API Web nella casella di ricerca.
- Selezionare il modello API Web ASP.NET Core e selezionare Avanti.
- Nella finestra di dialogo Configura il nuovo progetto assegnare al progetto il nome TodoApi e selezionare Avanti.
- Nella finestra di dialogo Informazioni aggiuntive:
- Verificare che Framework sia .NET 7.0 (o versione successiva).
- Verificare che la casella di controllo Usa controller (deselezionare per usare le API minime) sia selezionata.
- Seleziona Crea.
Nota
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.
Testare il progetto
Il modello di progetto crea un'API WeatherForecast
con supporto per Swagger.
Premere CTRL+F5 per l'esecuzione senza il debugger.
Visual Studio visualizza la finestra di dialogo seguente quando un progetto non è ancora configurato per l'uso di SSL:
Selezionare Sì se si considera attendibile il certificato SSL di IIS Express.
Verrà visualizzata la finestra di dialogo seguente:
Selezionare Sì se si accetta di considerare attendibile il certificato di sviluppo.
Per informazioni sull'attendibilità del browser Firefox, vedere Firefox edizione Standard C_ERROR_INADEQUATE_KEY_USAGE errore del certificato.
Visual Studio avvia il browser predefinito e passa a https://localhost:<port>/swagger/index.html
, dove <port>
è un numero di porta scelto in modo casuale.
Viene visualizzata la pagina /swagger/index.html
Swagger. Selezionare GET>Try it out>Execute (Esegui). La pagina visualizza:
- Comando Curl per testare l'API WeatherForecast.
- URL per testare l'API WeatherForecast.
- Codice di risposta, corpo e intestazioni.
- Casella di riepilogo a discesa con tipi di supporti e il valore e lo schema di esempio.
Se la pagina Swagger non viene visualizzata, vedere questo problema di GitHub.
Swagger viene usato per generare una documentazione utile e pagine della Guida per le API Web. Questa esercitazione è incentrata sulla creazione di un'API Web. Per altre informazioni su Swagger, vedere ASP.NET documentazione dell'API Web core con Swagger/OpenAPI.
Copiare e incollare l'URL della richiesta nel browser:https://localhost:<port>/weatherforecast
JSON simile all'esempio seguente viene restituito:
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Aggiungere una classe modello
Un modello è un set di classi che rappresentano i dati gestiti dall'app. Il modello per questa app è la TodoItem
classe .
- In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto. Selezionare Aggiungi>Nuova cartella. Denominare la cartella
Models
. - Fare clic con il pulsante destro del mouse sulla
Models
cartella e scegliere Aggiungi>classe. Assegnare alla classe il nome TodoItem e selezionare Aggiungi. - Sostituire il codice del modello con quanto segue:
namespace TodoApi.Models;
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
La proprietà Id
funziona come chiave univoca in un database relazionale.
Le classi di modello possono essere usate in qualsiasi punto del progetto, ma la Models
cartella viene usata per convenzione.
Aggiungere un contesto di database
Il contesto di database è la classe principale che coordina le funzionalità di Entity Framework per un modello di dati. Questa classe viene creata mediante derivazione dalla classe Microsoft.EntityFrameworkCore.DbContext.
Aggiungere i pacchetti NuGet di
- Scegliere NuGet Gestione pacchetti > Gestisci pacchetti NuGet per la soluzione dal menu Strumenti.
- Selezionare la scheda Sfoglia e quindi immettere
Microsoft.EntityFrameworkCore.InMemory
nella casella di ricerca. - Selezionare
Microsoft.EntityFrameworkCore.InMemory
nel riquadro sinistro. - Selezionare la casella di controllo Progetto nel riquadro destro e quindi selezionare Installa.
Aggiungere il contesto del database TodoContext
- Fare clic con il pulsante destro del mouse sulla
Models
cartella e scegliere Aggiungi>classe. Assegnare alla classe il nome TodoContext e fare clic su Aggiungi.
Immetti il codice seguente:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models; public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; }
Registrare il contesto del database
In ASP.NET Core i servizi come il contesto del database devono essere registrati con il contenitore di inserimento delle dipendenze. Il contenitore rende disponibile il servizio ai controller.
Eseguire l'aggiornamento Program.cs
con il codice evidenziato seguente:
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Il codice precedente:
- Aggiunge
using
direttive. - Aggiunge il contesto del database al contenitore di inserimento delle dipendenze.
- Specifica che il contesto del database userà un database in memoria.
Eseguire lo scaffolding di un controller
Fare clic con il pulsante destro del mouse sulla
Controllers
cartella.Selezionare Aggiungi>New Scaffolded Item.
Selezionare Controller API con azioni, che usa Entity Framework e quindi selezionare Aggiungi.
Nella finestra di dialogo Add API Controller with actions, using Entity Framework (Aggiungi controller API con azioni, che usa Entity Framework):
- Selezionare TodoItem (TodoApi.Models) nella classe Model.
- Selezionare TodoContext (TodoApi.Models) nella classe Contesto dati.
- Selezionare Aggiungi.
Se l'operazione di scaffolding non riesce, selezionare Aggiungi per provare a eseguire lo scaffolding una seconda volta.
Il codice generato:
- Contrassegna la classe con l'attributo
[ApiController]
. L'attributo indica che il controller risponde alle richieste di API Web. Per informazioni sui comportamenti specifici che l'attributo abilita, vedere Creare API Web con ASP.NET Core. - Usa l'inserimento delle dipendenze per inserire il contesto del database (
TodoContext
) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.
I modelli ASP.NET Core per:
- I controller con visualizzazioni includono
[action]
nel modello di route. - I controller API non includono
[action]
nel modello di route.
Quando il [action]
token non è incluso nel modello di route, il nome dell'azione (nome del metodo) non è incluso nell'endpoint. Ovvero, il nome del metodo associato dell'azione non viene usato nella route corrispondente.
Aggiornare il metodo di creazione PostTodoItem
Aggiornare l'istruzione return in PostTodoItem
per usare l'operatore nameof :
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
// return CreatedAtAction("PostTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(PostTodoItem), new { id = todoItem.Id }, todoItem);
}
Il codice precedente è un HTTP POST
metodo, come indicato dall'attributo [HttpPost]
. Il metodo ottiene il valore di TodoItem
dal corpo della richiesta HTTP.
Per altre informazioni, vedere Routing con attributi Http[verb].
Il metodo CreatedAtAction:
- Restituisce un codice di stato HTTP 201 se ha esito positivo.
HTTP 201
è la risposta standard per unHTTP POST
metodo che crea una nuova risorsa nel server. - Aggiunge un'intestazione Location alla risposta. L'intestazione
Location
specifica l'URI dell'elemento attività appena creato. Per altre informazioni, vedere 10.2.2 201 Created. - Fa riferimento all'azione
PostTodoItem
per creare l'URI dell'intestazioneLocation
. La parola chiavenameof
C# viene usata per evitare di impostare il nome dell'azione come hardcoded nella chiamata aCreatedAtAction
.
Test PostTodoItem
Premere CTRL+F5 per eseguire l'app.
Nella finestra del browser Swagger selezionare POST /api/TodoItems e quindi selezionare Prova.
Nella finestra Di input del corpo della richiesta aggiornare ONJS. ad esempio:
{ "name": "walk dog", "isComplete": true }
Selezionare Esegui
Testare l'URI dell'intestazione della posizione
Nell'articolo POST precedente, l'interfaccia utente di Swagger mostra l'intestazione della posizione in Intestazioni di risposta. Ad esempio: location: https://localhost:7260/api/TodoItems/1
. L'intestazione della posizione mostra l'URI della risorsa creata.
Per testare l'intestazione della posizione:
Nella finestra del browser Swagger selezionare GET /api/TodoItems/{id}, quindi selezionare Prova.
Immettere
1
nellaid
casella di input e quindi selezionare Esegui.
Esaminare i metodi GET
Vengono implementati due endpoint GET:
GET /api/todoitems
GET /api/todoitems/{id}
La sezione precedente ha mostrato un esempio della /api/todoitems/{id}
route.
Seguire le istruzioni POST per aggiungere un altro elemento todo e quindi testare la /api/todoitems
route usando Swagger.
Questa app usa un database in memoria. Se l'app viene arrestata e avviata, la richiesta GET precedente non restituirà alcun dato. Se non vengono restituiti dati, eseguire POST per pubblicare i dati nell'app.
Routing e percorsi di URL
L'attributo [HttpGet]
indica un metodo che risponde a una HTTP GET
richiesta. Il percorso dell'URL per ogni metodo viene costruito nel modo seguente:
Iniziare con la stringa di modello nell'attributo
Route
del controller:[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
Sostituire
[controller]
con il nome del controller, ovvero, per convenzione, il nome della classe controller meno il suffisso "Controller". In questo esempio il nome della classe controller è TodoItemsController, quindi il nome del controller è "TodoItems". Il routing ASP.NET Core non fa distinzione tra maiuscole e minuscole.Se l'attributo
[HttpGet]
ha un modello di route, ad esempio[HttpGet("products")]
, aggiungerlo al percorso. In questo esempio non si usa un modello. Per altre informazioni, vedere Routing con attributi Http[verb].
Nel metodo GetTodoItem
seguente, "{id}"
è una variabile segnaposto per l'identificatore univoco dell'elemento attività. Quando GetTodoItem
viene richiamato, il valore di "{id}"
nell'URL viene fornito al metodo nel relativo id
parametro.
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Valori restituiti
Il tipo restituito GetTodoItems
dei metodi e GetTodoItem
è Il tipo T> ActionResult<. ASP.NET Core serializza automaticamente l'oggetto in JSON e scrive JSON nel corpo del messaggio di risposta. Il codice di risposta per questo tipo restituito è 200 OK, presupponendo che non siano presenti eccezioni non gestite. Le eccezioni non gestite vengono convertite in errori 5xx.
I tipi restituiti ActionResult
possono rappresentare un ampio intervallo di codici di stato HTTP. Ad esempio, GetTodoItem
può restituire due valori di stato diversi:
- Se nessun elemento corrisponde all'ID richiesto, il metodo restituisce un codice di errore di statoNotFound 404.
- In caso contrario, il metodo restituisce 200 con un corpo della JSrisposta ON. La restituzione dei
item
risultati in unaHTTP 200
risposta.
Metodo PutTodoItem
Esaminare il metodo PutTodoItem
:
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
è simile a PostTodoItem
, ad eccezione del fatto che usa HTTP PUT
. La risposta è 204 (No Content). In base alla specifica HTTP, una PUT
richiesta richiede al client di inviare l'intera entità aggiornata, non solo le modifiche. Per supportare gli aggiornamenti parziali, usare HTTP PATCH.
Testare il metodo PutTodoItem
Questo esempio usa un database in memoria che deve essere inizializzato ogni volta che l'app viene avviata. Deve esistere un elemento nel database prima di eseguire una chiamata PUT. Chiamare GET per assicurarsi che nel database sia presente un elemento prima di effettuare una chiamata PUT.
Usando l'interfaccia utente di Swagger, usare il pulsante PUT per aggiornare l'oggetto TodoItem
con ID = 1 e impostarne il nome su "feed fish"
. Si noti che la risposta è HTTP 204 No Content
.
Metodo DeleteTodoItem
Esaminare il metodo DeleteTodoItem
:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
Testare il metodo DeleteTodoItem
Usare l'interfaccia utente di Swagger per eliminare l'oggetto TodoItem
con ID = 1. Si noti che la risposta è HTTP 204 No Content
.
Eseguire test con http-repl, Postman o curl
Http-repl, Postman e curl vengono spesso usati per testare le API. Swagger usa curl
e mostra il curl
comando inviato.
Per istruzioni su questi strumenti, vedere i collegamenti seguenti:
Per altre informazioni su http-repl
, vedere Testare le API Web con HttpRepl.
Impedire l'over-post
Attualmente l'app di esempio espone l'intero TodoItem
oggetto. Le app di produzione limitano in genere i dati di input e restituiti usando un subset del modello. Ci sono diversi motivi alla base di questo, e la sicurezza è una delle principali. Il subset di un modello viene in genere definito DTO (Data Transfer Object), modello di input o modello di visualizzazione. DTO viene usato in questa esercitazione.
Un DTO può essere usato per:
- Impedire l'over-post.
- Nascondere le proprietà che i client non devono visualizzare.
- Omettere alcune proprietà per ridurre le dimensioni del payload.
- Appiattire gli oggetti grafici che contengono oggetti annidati. Gli oggetti grafici appiattiti possono essere più pratici per i client.
Per illustrare l'approccio DTO, aggiornare la TodoItem
classe in modo da includere un campo segreto:
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
}
Il campo segreto deve essere nascosto da questa app, ma un'app amministrativa potrebbe scegliere di esporla.
Verificare che sia possibile pubblicare e ottenere il campo segreto.
Creare un modello DTO:
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Aggiornare per TodoItemsController
usare TodoItemDTO
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers;
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
// <snippet_GetByID>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// </snippet_GetByID>
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Update>
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
{
if (id != todoDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoDTO.Name;
todoItem.IsComplete = todoDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// </snippet_Update>
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
// <snippet_Create>
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoDTO.IsComplete,
Name = todoDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// </snippet_Create>
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
Verificare che non sia possibile pubblicare o ottenere il campo segreto.
Chiamare l'API Web con JavaScript
Vedere Esercitazione: Chiamare un'API Web ASP.NET Core con JavaScript.
Serie di video dell'API Web
Vedere Video: Beginner's Series to: Web APIs (Serie per principianti: API Web).
Modelli di app Web affidabili
Per indicazioni sulla creazione di un'app moderna, affidabile, affidabile, affidabile, testabile, conveniente e scalabile ASP.NET Core, indipendentemente dal fatto che si tratti di un'app esistente o di refactoring di un'app esistente, vedi Modello di app Web Reliable Web for.NETYouTube.
Aggiungere il supporto per l'autenticazione a un'API Web
ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web core ASP.NET. Per proteggere le API Web e i contratti a pagina singola, usare una delle opzioni seguenti:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server è un framework OpenID Connessione 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).
Pubblicare in Azure
Per informazioni sulla distribuzione in Azure, vedere Avvio rapido: Distribuire un'app Web ASP.NET.
Risorse aggiuntive
Visualizzare o scaricare il codice di esempio per questa esercitazione. Vedere come scaricare un esempio.
Per ulteriori informazioni, vedi le seguenti risorse:
- Creare API Web con ASP.NET Core
- Esercitazione: Creare un'API minima con ASP.NET Core
- Documentazione delle API Web ASP.NET Core con Swagger/OpenAPI
- Razor Pagine con Entity Framework Core in ASP.NET Core - Esercitazione 1 di 8
- Routing alle azioni del controller in ASP.NET Core
- Tipi restituiti dall'azione del controller nell'API Web ASP.NET Core
- Distribuire le app ASP.NET Core in Servizio app di Azure
- Ospitare e distribuire ASP.NET Core
- Creare un'API Web con ASP.NET Core
Questa esercitazione illustra le nozioni di base per la creazione di un'API Web basata su controller che usa un database. Un altro approccio alla creazione di API in ASP.NET Core consiste nel creare API minime. Per informazioni sulla scelta tra API minime e API basate su controller, vedere Panoramica delle API. Per un'esercitazione sulla creazione di un'API minima, vedere Esercitazione: Creare un'API minima con ASP.NET Core.
In questa esercitazione apprenderai a:
- Creare un progetto di API Web.
- Aggiungere una classe modello e un contesto di database.
- Eseguire lo scaffolding di un controller con i metodi CRUD.
- Configurare il routing, i percorsi URL e i valori restituiti.
- Chiamare l'API Web con http-repl.
Al termine si avrà un'API Web che può gestire gli elementi di tipo "attività" archiviati in un database.
Panoramica
Questa esercitazione consente di creare l'API seguente:
API | Descrizione | Testo della richiesta | Corpo della risposta |
---|---|---|---|
GET /api/todoitems |
Ottiene tutti gli elementi attività | None | Matrice di elementi attività |
GET /api/todoitems/{id} |
Ottiene un elemento in base all'ID | None | Elemento attività |
POST /api/todoitems |
Aggiunge un nuovo elemento | Elemento attività | Elemento attività |
PUT /api/todoitems/{id} |
Aggiorna un elemento esistente | Elemento attività | None |
DELETE /api/todoitems/{id} |
Elimina un elemento | None | None |
Il diagramma seguente visualizza la struttura dell'app.
Prerequisiti
- Visual Studio 2022 con il carico di lavoro Sviluppo ASP.NET e Web.
- .NET 6.0 SDK
Creare un progetto Web
- Scegliere Nuovo>Progetto dal menu File.
- Immettere l'API Web nella casella di ricerca.
- Selezionare il modello API Web ASP.NET Core e selezionare Avanti.
- Nella finestra di dialogo Configura il nuovo progetto assegnare al progetto il nome TodoApi e selezionare Avanti.
- Nella finestra di dialogo Informazioni aggiuntive:
- Verificare che Framework sia .NET 6.0 (supporto a lungo termine).
- Verificare che la casella di controllo Usa controller (deselezionare per usare le API minime) sia selezionata.
- Seleziona Crea.
Nota
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.
Testare il progetto
Il modello di progetto crea un'API WeatherForecast
con supporto per Swagger.
Premere CTRL+F5 per l'esecuzione senza il debugger.
Visual Studio visualizza la finestra di dialogo seguente quando un progetto non è ancora configurato per l'uso di SSL:
Selezionare Sì se si considera attendibile il certificato SSL di IIS Express.
Verrà visualizzata la finestra di dialogo seguente:
Selezionare Sì se si accetta di considerare attendibile il certificato di sviluppo.
Per informazioni sull'attendibilità del browser Firefox, vedere Firefox edizione Standard C_ERROR_INADEQUATE_KEY_USAGE errore del certificato.
Visual Studio avvia il browser predefinito e passa a https://localhost:<port>/swagger/index.html
, dove <port>
è un numero di porta scelto in modo casuale.
Viene visualizzata la pagina /swagger/index.html
Swagger. Selezionare GET>Try it out>Execute (Esegui). La pagina visualizza:
- Comando Curl per testare l'API WeatherForecast.
- URL per testare l'API WeatherForecast.
- Codice di risposta, corpo e intestazioni.
- Casella di riepilogo a discesa con tipi di supporti e il valore e lo schema di esempio.
Se la pagina Swagger non viene visualizzata, vedere questo problema di GitHub.
Swagger viene usato per generare una documentazione utile e pagine della Guida per le API Web. Questa esercitazione è incentrata sulla creazione di un'API Web. Per altre informazioni su Swagger, vedere ASP.NET documentazione dell'API Web core con Swagger/OpenAPI.
Copiare e incollare l'URL della richiesta nel browser:https://localhost:<port>/weatherforecast
JSON simile all'esempio seguente viene restituito:
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Aggiornare launchUrl
In Proprietà\launch Impostazioni.json aggiornare launchUrl
da "swagger"
a "api/todoitems"
:
"launchUrl": "api/todoitems",
Poiché Swagger verrà rimosso, il markup precedente modifica l'URL avviato al metodo GET del controller aggiunto nelle sezioni seguenti.
Aggiungere una classe modello
Un modello è un set di classi che rappresentano i dati gestiti dall'app. Il modello per questa app è una classe TodoItem
singola.
In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto. Selezionare Aggiungi>Nuova cartella. Denominare la cartella
Models
.Fare clic con il pulsante destro del mouse sulla
Models
cartella e scegliere Aggiungi>classe. Assegnare alla classe il nome TodoItem e selezionare Aggiungi.Sostituire il codice del modello con quanto segue:
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
}
La proprietà Id
funziona come chiave univoca in un database relazionale.
Le classi di modello possono essere usate in qualsiasi punto del progetto, ma la Models
cartella viene usata per convenzione.
Aggiungere un contesto di database
Il contesto di database è la classe principale che coordina le funzionalità di Entity Framework per un modello di dati. Questa classe viene creata mediante derivazione dalla classe Microsoft.EntityFrameworkCore.DbContext.
Aggiungere i pacchetti NuGet di
- Scegliere NuGet Gestione pacchetti > Gestisci pacchetti NuGet per la soluzione dal menu Strumenti.
- Selezionare la scheda Sfoglia e quindi immettere
Microsoft.EntityFrameworkCore.InMemory
nella casella di ricerca. - Selezionare
Microsoft.EntityFrameworkCore.InMemory
nel riquadro sinistro. - Selezionare la casella di controllo Progetto nel riquadro destro e quindi selezionare Installa.
Aggiungere il contesto del database TodoContext
- Fare clic con il pulsante destro del mouse sulla
Models
cartella e scegliere Aggiungi>classe. Assegnare alla classe il nome TodoContext e fare clic su Aggiungi.
Immetti il codice seguente:
using Microsoft.EntityFrameworkCore; using System.Diagnostics.CodeAnalysis; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } = null!; } }
Registrare il contesto del database
In ASP.NET Core i servizi come il contesto del database devono essere registrati con il contenitore di inserimento delle dipendenze. Il contenitore rende disponibile il servizio ai controller.
Aggiornare Program.cs
con il codice seguente:
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
//builder.Services.AddSwaggerGen(c =>
//{
// c.SwaggerDoc("v1", new() { Title = "TodoApi", Version = "v1" });
//});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (builder.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//app.UseSwagger(); // UseSwaggerUI Protected by if (env.IsDevelopment())
//app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TodoApi v1"));
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Il codice precedente:
- Rimuove le chiamate Swagger.
- Rimuove le direttive inutilizzate
using
. - Aggiunge il contesto del database al contenitore di inserimento delle dipendenze.
- Specifica che il contesto del database userà un database in memoria.
Eseguire lo scaffolding di un controller
Fare clic con il pulsante destro del mouse sulla
Controllers
cartella.Selezionare Aggiungi>New Scaffolded Item.
Selezionare Controller API con azioni, che usa Entity Framework e quindi selezionare Aggiungi.
Nella finestra di dialogo Add API Controller with actions, using Entity Framework (Aggiungi controller API con azioni, che usa Entity Framework):
- Selezionare TodoItem (TodoApi.Models) nella classe Model.
- Selezionare TodoContext (TodoApi.Models) nella classe Contesto dati.
- Selezionare Aggiungi.
Se l'operazione di scaffolding non riesce, selezionare Aggiungi per provare a eseguire lo scaffolding una seconda volta.
Il codice generato:
- Contrassegna la classe con l'attributo
[ApiController]
. L'attributo indica che il controller risponde alle richieste di API Web. Per informazioni sui comportamenti specifici che l'attributo abilita, vedere Creare API Web con ASP.NET Core. - Usa l'inserimento delle dipendenze per inserire il contesto del database (
TodoContext
) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.
I modelli ASP.NET Core per:
- I controller con visualizzazioni includono
[action]
nel modello di route. - I controller API non includono
[action]
nel modello di route.
Quando il [action]
token non è incluso nel modello di route, il nome dell'azione viene escluso dalla route. Ovvero, il nome del metodo associato dell'azione non viene usato nella route corrispondente.
Aggiornare il metodo di creazione PostTodoItem
Aggiornare l'istruzione return in PostTodoItem
per usare l'operatore nameof :
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
//return CreatedAtAction("PostTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(PostTodoItem), new { id = todoItem.Id }, todoItem);
}
Il codice precedente è un metodo HTTP POST, come indicato dall'attributo [HttpPost]
. Il metodo ottiene il valore dell'elemento attività dal corpo della richiesta HTTP.
Per altre informazioni, vedere Routing con attributi Http[verb].
Il metodo CreatedAtAction:
- Restituisce un codice di stato HTTP 201 se ha esito positivo. HTTP 201 è la risposta standard per un metodo HTTP POST che crea una nuova risorsa nel server.
- Aggiunge un'intestazione Location alla risposta. L'intestazione
Location
specifica l'URI dell'elemento attività appena creato. Per altre informazioni, vedere 10.2.2 201 Created. - Fa riferimento all'azione
GetTodoItem
per creare l'URI dell'intestazioneLocation
. La parola chiavenameof
C# viene usata per evitare di impostare il nome dell'azione come hardcoded nella chiamata aCreatedAtAction
.
Installare http-repl
Questa esercitazione usa http-repl per testare l'API Web.
Al prompt dei comandi eseguire il comando seguente:
dotnet tool install -g Microsoft.dotnet-httprepl
Nota
Per impostazione predefinita, l'architettura dei file binari .NET da installare rappresenta l'architettura del sistema operativo attualmente in esecuzione. Per specificare un'architettura del sistema operativo diversa, vedere dotnet tool install, --opzione arch.. Per altre informazioni, vedere Problema di GitHub dotnet/AspNetCore.Docs #29262.
Se non è installato .NET 6.0 SDK o runtime, installare il runtime .NET 6.0.
Test PostTodoItem
Premere CTRL+F5 per eseguire l'app.
Aprire una nuova finestra del terminale ed eseguire i comandi seguenti. Se l'app usa un numero di porta diverso, sostituire 5001 nel comando httprepl con il numero di porta.
httprepl https://localhost:5001/api/todoitems post -h Content-Type=application/json -c "{"name":"walk dog","isComplete":true}"
Ecco un esempio dell'output del comando :
HTTP/1.1 201 Created Content-Type: application/json; charset=utf-8 Date: Tue, 07 Sep 2021 20:39:47 GMT Location: https://localhost:5001/api/TodoItems/1 Server: Kestrel Transfer-Encoding: chunked { "id": 1, "name": "walk dog", "isComplete": true }
Testare l'URI dell'intestazione della posizione
Per testare l'intestazione della posizione, copiarlo e incollarlo in un comando httprepl get
.
L'esempio seguente presuppone che si sia ancora in una sessione httprepl. Se è stata terminata la sessione httprepl precedente, sostituire connect
con httprepl
nei comandi seguenti:
connect https://localhost:5001/api/todoitems/1
get
Ecco un esempio dell'output del comando :
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Tue, 07 Sep 2021 20:48:10 GMT
Server: Kestrel
Transfer-Encoding: chunked
{
"id": 1,
"name": "walk dog",
"isComplete": true
}
Esaminare i metodi GET
Vengono implementati due endpoint GET:
GET /api/todoitems
GET /api/todoitems/{id}
È stato appena visto un esempio del /api/todoitems/{id}
percorso. Testare la /api/todoitems
route:
connect https://localhost:5001/api/todoitems
get
Ecco un esempio dell'output del comando :
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Tue, 07 Sep 2021 20:59:21 GMT
Server: Kestrel
Transfer-Encoding: chunked
[
{
"id": 1,
"name": "walk dog",
"isComplete": true
}
]
Questa volta, on JSrestituito è una matrice di un elemento.
Questa app usa un database in memoria. Se l'app viene arrestata e avviata, la richiesta GET precedente non restituirà alcun dato. Se non vengono restituiti dati, eseguire POST per pubblicare i dati nell'app.
Routing e percorsi di URL
L'attributo [HttpGet]
indica un metodo che risponde a una richiesta HTTP GET. Il percorso dell'URL per ogni metodo viene costruito nel modo seguente:
Iniziare con la stringa di modello nell'attributo
Route
del controller:[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase
Sostituire
[controller]
con il nome del controller, ovvero, per convenzione, il nome della classe controller meno il suffisso "Controller". In questo esempio il nome della classe controller è TodoItemsController, quindi il nome del controller è "TodoItems". Il routing ASP.NET Core non fa distinzione tra maiuscole e minuscole.Se l'attributo
[HttpGet]
ha un modello di route, ad esempio[HttpGet("products")]
, aggiungerlo al percorso. In questo esempio non si usa un modello. Per altre informazioni, vedere Routing con attributi Http[verb].
Nel metodo GetTodoItem
seguente, "{id}"
è una variabile segnaposto per l'identificatore univoco dell'elemento attività. Quando GetTodoItem
viene richiamato, il valore di "{id}"
nell'URL viene fornito al metodo nel relativo id
parametro.
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Valori restituiti
Il tipo restituito GetTodoItems
dei metodi e GetTodoItem
è Il tipo T> ActionResult<. ASP.NET Core serializza automaticamente l'oggetto in JSON e scrive JSON nel corpo del messaggio di risposta. Il codice di risposta per questo tipo restituito è 200 OK, presupponendo che non siano presenti eccezioni non gestite. Le eccezioni non gestite vengono convertite in errori 5xx.
I tipi restituiti ActionResult
possono rappresentare un ampio intervallo di codici di stato HTTP. Ad esempio, GetTodoItem
può restituire due valori di stato diversi:
- Se nessun elemento corrisponde all'ID richiesto, il metodo restituisce un codice di errore di statoNotFound 404.
- In caso contrario, il metodo restituisce 200 con un corpo della JSrisposta ON. La restituzione di
item
risulta in una risposta HTTP 200.
Metodo PutTodoItem
Esaminare il metodo PutTodoItem
:
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
è simile a PostTodoItem
ma usa la richiesta HTTP PUT. La risposta è 204 (No Content). In base alla specifica HTTP, una richiesta PUT richiede che il client invii l'intera entità aggiornata e non solo le modifiche. Per supportare gli aggiornamenti parziali, usare HTTP PATCH.
Se viene visualizzato un errore durante la chiamata PutTodoItem
nella sezione seguente, chiamare GET
per assicurarsi che nel database sia presente un elemento.
Testare il metodo PutTodoItem
Questo esempio usa un database in memoria che deve essere inizializzato ogni volta che l'app viene avviata. Deve esistere un elemento nel database prima di eseguire una chiamata PUT. Chiamare GET per assicurarsi che nel database sia presente un elemento prima di effettuare una chiamata PUT.
Aggiornare l'elemento attività con ID = 1 e impostarne il nome su "feed fish"
:
connect https://localhost:5001/api/todoitems/1
put -h Content-Type=application/json -c "{"id":1,"name":"feed fish","isComplete":true}"
Ecco un esempio dell'output del comando :
HTTP/1.1 204 No Content
Date: Tue, 07 Sep 2021 21:20:47 GMT
Server: Kestrel
Metodo DeleteTodoItem
Esaminare il metodo DeleteTodoItem
:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
Testare il metodo DeleteTodoItem
Eliminare l'elemento attività con ID = 1:
connect https://localhost:5001/api/todoitems/1
delete
Ecco un esempio dell'output del comando :
HTTP/1.1 204 No Content
Date: Tue, 07 Sep 2021 21:43:00 GMT
Server: Kestrel
Impedire l'over-post
Attualmente l'app di esempio espone l'intero TodoItem
oggetto. Le app di produzione limitano in genere i dati di input e restituiti usando un subset del modello. Ci sono diversi motivi alla base di questo, e la sicurezza è una delle principali. Il subset di un modello viene in genere definito DTO (Data Transfer Object), modello di input o modello di visualizzazione. DTO viene usato in questa esercitazione.
Un DTO può essere usato per:
- Impedire l'over-post.
- Nascondere le proprietà che i client non devono visualizzare.
- Omettere alcune proprietà per ridurre le dimensioni del payload.
- Appiattire gli oggetti grafici che contengono oggetti annidati. Gli oggetti grafici appiattiti possono essere più pratici per i client.
Per illustrare l'approccio DTO, aggiornare la TodoItem
classe in modo da includere un campo segreto:
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
public string? Secret { get; set; }
}
}
Il campo segreto deve essere nascosto da questa app, ma un'app amministrativa potrebbe scegliere di esporla.
Verificare che sia possibile pubblicare e ottenere il campo segreto.
Creare un modello DTO:
namespace TodoApi.Models
{
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
}
Aggiornare per TodoItemsController
usare TodoItemDTO
:
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
private readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
// GET: api/TodoItems/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
// PUT: api/TodoItems/5
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
if (id != todoItemDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoItemDTO.Name;
todoItem.IsComplete = todoItemDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
// POST: api/TodoItems
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> CreateTodoItem(TodoItemDTO todoItemDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id)
{
return _context.TodoItems.Any(e => e.Id == id);
}
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
}
Verificare che non sia possibile pubblicare o ottenere il campo segreto.
Chiamare l'API Web con JavaScript
Vedere Esercitazione: Chiamare un'API Web ASP.NET Core con JavaScript.
Serie di video dell'API Web
Vedere Video: Beginner's Series to: Web APIs (Serie per principianti: API Web).
Aggiungere il supporto per l'autenticazione a un'API Web
ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web core ASP.NET. Per proteggere le API Web e i contratti a pagina singola, usare una delle opzioni seguenti:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server è un framework OpenID Connessione 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).
Pubblicare in Azure
Per informazioni sulla distribuzione in Azure, vedere Avvio rapido: Distribuire un'app Web ASP.NET.
Risorse aggiuntive
Visualizzare o scaricare il codice di esempio per questa esercitazione. Vedere come scaricare un esempio.
Per ulteriori informazioni, vedi le seguenti risorse:
- Creare API Web con ASP.NET Core
- Esercitazione: Creare un'API minima con ASP.NET Core
- Documentazione delle API Web ASP.NET Core con Swagger/OpenAPI
- Razor Pagine con Entity Framework Core in ASP.NET Core - Esercitazione 1 di 8
- Routing alle azioni del controller in ASP.NET Core
- Tipi restituiti dall'azione del controller nell'API Web ASP.NET Core
- Distribuire le app ASP.NET Core in Servizio app di Azure
- Ospitare e distribuire ASP.NET Core
- Creare un'API Web con ASP.NET Core
Questa esercitazione illustra le nozioni di base per la creazione di un'API Web basata su controller che usa un database. Un altro approccio alla creazione di API in ASP.NET Core consiste nel creare API minime. Per informazioni sulla scelta tra API minime e API basate su controller, vedere Panoramica delle API. Per un'esercitazione sulla creazione di un'API minima, vedere Esercitazione: Creare un'API minima con ASP.NET Core.
In questa esercitazione apprenderai a:
- Creare un progetto di API Web.
- Aggiungere una classe modello e un contesto di database.
- Eseguire lo scaffolding di un controller con i metodi CRUD.
- Configurare il routing, i percorsi URL e i valori restituiti.
- Chiamare l'API Web con Postman.
Al termine si avrà un'API Web che può gestire gli elementi di tipo "attività" archiviati in un database.
Panoramica
Questa esercitazione consente di creare l'API seguente:
API | Descrizione | Testo della richiesta | Corpo della risposta |
---|---|---|---|
GET /api/todoitems |
Ottiene tutti gli elementi attività | None | Matrice di elementi attività |
GET /api/todoitems/{id} |
Ottiene un elemento in base all'ID | None | Elemento attività |
POST /api/todoitems |
Aggiunge un nuovo elemento | Elemento attività | Elemento attività |
PUT /api/todoitems/{id} |
Aggiorna un elemento esistente | Elemento attività | None |
DELETE /api/todoitems/{id} |
Elimina un elemento | None | None |
Il diagramma seguente visualizza la struttura dell'app.
Prerequisiti
- Visual Studio 2019 16.8 o versione successiva con il carico di lavoro Sviluppo ASP.NET e Web
- .NET 5.0 SDK
Creare un progetto Web
- Scegliere Nuovo>Progetto dal menu File.
- Selezionare il modello api Web core ASP.NET e fare clic su Avanti.
- Assegnare al progetto il nome TodoApi e fare clic su Crea.
- Nella finestra di dialogo Crea una nuova applicazione Web ASP.NET Core verificare che siano selezionati .NET Core e ASP.NET Core 5.0. Selezionare il modello API e fare clic su Crea.
Nota
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.
Testare il progetto
Il modello di progetto crea un'API WeatherForecast
con supporto per Swagger.
Premere CTRL+F5 per l'esecuzione senza il debugger.
Visual Studio visualizza la finestra di dialogo seguente quando un progetto non è ancora configurato per l'uso di SSL:
Selezionare Sì se si considera attendibile il certificato SSL di IIS Express.
Verrà visualizzata la finestra di dialogo seguente:
Selezionare Sì se si accetta di considerare attendibile il certificato di sviluppo.
Per informazioni sull'attendibilità del browser Firefox, vedere Firefox edizione Standard C_ERROR_INADEQUATE_KEY_USAGE errore del certificato.
Avvio di Visual Studio:
- Server Web IIS Express.
- Il browser predefinito e passa a
https://localhost:<port>/swagger/index.html
, dove<port>
è un numero di porta scelto in modo casuale.
Viene visualizzata la pagina /swagger/index.html
Swagger. Selezionare GET>Try it out>Execute (Esegui). La pagina visualizza:
- Comando Curl per testare l'API WeatherForecast.
- URL per testare l'API WeatherForecast.
- Codice di risposta, corpo e intestazioni.
- Casella di riepilogo a discesa con tipi di supporti e il valore e lo schema di esempio.
Se la pagina Swagger non viene visualizzata, vedere questo problema di GitHub.
Swagger viene usato per generare una documentazione utile e pagine della Guida per le API Web. Questa esercitazione è incentrata sulla creazione di un'API Web. Per altre informazioni su Swagger, vedere ASP.NET documentazione dell'API Web core con Swagger/OpenAPI.
Copiare e incollare l'URL della richiesta nel browser:https://localhost:<port>/weatherforecast
JSON simile al seguente viene restituito:
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Aggiornare launchUrl
In Proprietà\launch Impostazioni.json aggiornare launchUrl
da "swagger"
a "api/todoitems"
:
"launchUrl": "api/todoitems",
Poiché Swagger verrà rimosso, il markup precedente modifica l'URL avviato al metodo GET del controller aggiunto nelle sezioni seguenti.
Aggiungere una classe modello
Un modello è un set di classi che rappresentano i dati gestiti dall'app. Il modello per questa app è una classe TodoItem
singola.
In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto. Selezionare Aggiungi>Nuova cartella. Denominare la cartella
Models
.Fare clic con il pulsante destro del mouse sulla
Models
cartella e scegliere Aggiungi>classe. Assegnare alla classe il nome TodoItem e selezionare Aggiungi.Sostituire il codice del modello con quanto segue:
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
}
La proprietà Id
funziona come chiave univoca in un database relazionale.
Le classi di modello possono essere usate in qualsiasi punto del progetto, ma la Models
cartella viene usata per convenzione.
Aggiungere un contesto di database
Il contesto di database è la classe principale che coordina le funzionalità di Entity Framework per un modello di dati. Questa classe viene creata mediante derivazione dalla classe Microsoft.EntityFrameworkCore.DbContext.
Aggiungere i pacchetti NuGet di
- Scegliere NuGet Gestione pacchetti > Gestisci pacchetti NuGet per la soluzione dal menu Strumenti.
- Selezionare la scheda Sfoglia e quindi immettere
Microsoft.EntityFrameworkCore.InMemory
nella casella di ricerca. - Selezionare
Microsoft.EntityFrameworkCore.InMemory
nel riquadro sinistro. - Selezionare la casella di controllo Progetto nel riquadro destro e quindi selezionare Installa.
Aggiungere il contesto del database TodoContext
- Fare clic con il pulsante destro del mouse sulla
Models
cartella e scegliere Aggiungi>classe. Assegnare alla classe il nome TodoContext e fare clic su Aggiungi.
Immetti il codice seguente:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } } }
Registrare il contesto del database
In ASP.NET Core i servizi come il contesto del database devono essere registrati con il contenitore di inserimento delle dipendenze. Il contenitore rende disponibile il servizio ai controller.
Aggiornare Startup.cs
con il codice seguente:
// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
//services.AddSwaggerGen(c =>
//{
// c.SwaggerDoc("v1", new OpenApiInfo { Title = "TodoApi", Version = "v1" });
//});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//app.UseSwagger(); // UseSwaggerUI Protected by if (env.IsDevelopment())
//app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TodoApi v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Il codice precedente:
- Rimuove le chiamate Swagger.
- Rimuove le dichiarazioni
using
inutilizzate. - Aggiunge il contesto del database al contenitore di inserimento delle dipendenze.
- Specifica che il contesto del database userà un database in memoria.
Eseguire lo scaffolding di un controller
Fare clic con il pulsante destro del mouse sulla
Controllers
cartella.Selezionare Aggiungi>New Scaffolded Item.
Selezionare Controller API con azioni, che usa Entity Framework e quindi selezionare Aggiungi.
Nella finestra di dialogo Add API Controller with actions, using Entity Framework (Aggiungi controller API con azioni, che usa Entity Framework):
- Selezionare TodoItem (TodoApi.Models) nella classe Model.
- Selezionare TodoContext (TodoApi.Models) nella classe Contesto dati.
- Selezionare Aggiungi.
Il codice generato:
- Contrassegna la classe con l'attributo
[ApiController]
. L'attributo indica che il controller risponde alle richieste di API Web. Per informazioni sui comportamenti specifici che l'attributo abilita, vedere Creare API Web con ASP.NET Core. - Usa l'inserimento delle dipendenze per inserire il contesto del database (
TodoContext
) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.
I modelli ASP.NET Core per:
- I controller con visualizzazioni includono
[action]
nel modello di route. - I controller API non includono
[action]
nel modello di route.
Quando il [action]
token non è incluso nel modello di route, il nome dell'azione viene escluso dalla route. Ovvero, il nome del metodo associato dell'azione non viene usato nella route corrispondente.
Aggiornare il metodo di creazione PostTodoItem
Aggiornare l'istruzione return in PostTodoItem
per usare l'operatore nameof :
// POST: api/TodoItems
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
//return CreatedAtAction("PostTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(PostTodoItem), new { id = todoItem.Id }, todoItem);
}
Il codice precedente è un metodo HTTP POST, come indicato dall'attributo [HttpPost]
. Il metodo ottiene il valore dell'elemento attività dal corpo della richiesta HTTP.
Per altre informazioni, vedere Routing con attributi Http[verb].
Il metodo CreatedAtAction:
- Restituisce un codice di stato HTTP 201 se ha esito positivo. HTTP 201 è la risposta standard per un metodo HTTP POST che crea una nuova risorsa nel server.
- Aggiunge un'intestazione Location alla risposta. L'intestazione
Location
specifica l'URI dell'elemento attività appena creato. Per altre informazioni, vedere 201 Created. - Fa riferimento all'azione
GetTodoItem
per creare l'URI dell'intestazioneLocation
. La parola chiavenameof
C# viene usata per evitare di impostare il nome dell'azione come hardcoded nella chiamata aCreatedAtAction
.
Installare Postman
Questa esercitazione usa Postman per testare l'API Web.
- Installare Postman
- Avviare l'app Web.
- Avviare Postman.
- Disabilitare la verifica del certificato SSL:
- Postman per Windows: selezionare File> Impostazioni (scheda Generale), disabilitare la verifica del certificato SSL.
- Postman per macOS: selezionare Postman> Impostazioni (scheda Generale), disabilitare la verifica del certificato SSL.
Avviso
Riattivare la verifica dei certificati SSL al termine del test del controller.
Testare PostTodoItem con Postman
Creare una nuova richiesta.
Impostare il metodo HTTP su
POST
.Impostare l'URI su
https://localhost:<port>/api/todoitems
. Ad esempio:https://localhost:5001/api/todoitems
.Selezionare la scheda Corpo.
Selezionare il pulsante di opzione raw (non elaborato).
Impostare il tipo su JSON (application/json).
Nel corpo della richiesta immettere JSON per un elemento attività:
{ "name":"walk dog", "isComplete":true }
Selezionare Invia.
Testare l'URI dell'intestazione della posizione
L'URI dell'intestazione della posizione può essere testato nel browser. Copiare e incollare l'URI dell'intestazione della posizione nel browser.
Per eseguire il test in Postman:
Selezionare la scheda Headers (Intestazioni) nel riquadro Response (Risposta).
Copiare il valore dell'intestazione Location (Posizione):
Impostare il metodo HTTP su
GET
.Impostare l'URI su
https://localhost:<port>/api/todoitems/1
. Ad esempio:https://localhost:5001/api/todoitems/1
.Selezionare Invia.
Esaminare i metodi GET
Vengono implementati due endpoint GET:
GET /api/todoitems
GET /api/todoitems/{id}
Testare l'app chiamando i due endpoint da un browser o da Postman. Ad esempio:
https://localhost:5001/api/todoitems
https://localhost:5001/api/todoitems/1
Una risposta simile alla seguente viene generata dalla chiamata a GetTodoItems
:
[
{
"id": 1,
"name": "Item1",
"isComplete": false
}
]
Testare Get con Postman
- Creare una nuova richiesta.
- Impostare il metodo HTTP su GET.
- Impostare l'URI della richiesta su
https://localhost:<port>/api/todoitems
. Ad esempio:https://localhost:5001/api/todoitems
. - Impostare Two pane view (Visualizzazione in due riquadri) in Postman.
- Selezionare Invia.
Questa app usa un database in memoria. Se l'app viene arrestata e avviata, la richiesta GET precedente non restituirà alcun dato. Se non vengono restituiti dati, eseguire POST per pubblicare i dati nell'app.
Routing e percorsi di URL
L'attributo [HttpGet]
indica un metodo che risponde a una richiesta HTTP GET. Il percorso dell'URL per ogni metodo viene costruito nel modo seguente:
Iniziare con la stringa di modello nell'attributo
Route
del controller:[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase { private readonly TodoContext _context; public TodoItemsController(TodoContext context) { _context = context; }
Sostituire
[controller]
con il nome del controller, ovvero, per convenzione, il nome della classe controller meno il suffisso "Controller". In questo esempio il nome della classe controller è TodoItemsController, quindi il nome del controller è "TodoItems". Il routing ASP.NET Core non fa distinzione tra maiuscole e minuscole.Se l'attributo
[HttpGet]
ha un modello di route, ad esempio[HttpGet("products")]
, aggiungerlo al percorso. In questo esempio non si usa un modello. Per altre informazioni, vedere Routing con attributi Http[verb].
Nel metodo GetTodoItem
seguente, "{id}"
è una variabile segnaposto per l'identificatore univoco dell'elemento attività. Quando GetTodoItem
viene richiamato, il valore di "{id}"
nell'URL viene fornito al metodo nel relativo id
parametro.
// GET: api/TodoItems/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Valori restituiti
Il tipo restituito GetTodoItems
dei metodi e GetTodoItem
è Il tipo T> ActionResult<. ASP.NET Core serializza automaticamente l'oggetto in JSON e scrive JSON nel corpo del messaggio di risposta. Il codice di risposta per questo tipo restituito è 200 OK, presupponendo che non siano presenti eccezioni non gestite. Le eccezioni non gestite vengono convertite in errori 5xx.
I tipi restituiti ActionResult
possono rappresentare un ampio intervallo di codici di stato HTTP. Ad esempio, GetTodoItem
può restituire due valori di stato diversi:
- Se nessun elemento corrisponde all'ID richiesto, il metodo restituisce un codice di errore di statoNotFound 404.
- In caso contrario, il metodo restituisce 200 con un corpo della JSrisposta ON. La restituzione di
item
risulta in una risposta HTTP 200.
Metodo PutTodoItem
Esaminare il metodo PutTodoItem
:
// PUT: api/TodoItems/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
è simile a PostTodoItem
ma usa la richiesta HTTP PUT. La risposta è 204 (No Content). In base alla specifica HTTP, una richiesta PUT richiede che il client invii l'intera entità aggiornata e non solo le modifiche. Per supportare gli aggiornamenti parziali, usare HTTP PATCH.
Se si riceve un errore chiamando PutTodoItem
, chiamare GET
per verificare che il database includa un elemento.
Testare il metodo PutTodoItem
Questo esempio usa un database in memoria che deve essere inizializzato ogni volta che l'app viene avviata. Deve esistere un elemento nel database prima di eseguire una chiamata PUT. Chiamare GET per assicurarsi che nel database sia presente un elemento prima di effettuare una chiamata PUT.
Aggiornare l'elemento attività con ID = 1 e impostarne il nome su "feed fish"
:
{
"Id":1,
"name":"feed fish",
"isComplete":true
}
L'immagine seguente visualizza l'aggiornamento di Postman:
Metodo DeleteTodoItem
Esaminare il metodo DeleteTodoItem
:
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
Testare il metodo DeleteTodoItem
Usare Postman per eliminare un elemento attività:
- Impostare il metodo su
DELETE
. - Impostare l'URI dell'oggetto da eliminare, ad esempio
https://localhost:5001/api/todoitems/1
. - Selezionare Invia.
Impedire l'over-post
Attualmente l'app di esempio espone l'intero TodoItem
oggetto. Le app di produzione limitano in genere i dati di input e restituiti usando un subset del modello. Esistono diversi motivi alla base di questa situazione e la sicurezza è una delle principali. Il subset di un modello viene in genere definito DTO (Data Transfer Object), modello di input o modello di visualizzazione. DTO viene usato in questo articolo.
Un DTO può essere usato per:
- Impedire l'over-post.
- Nascondere le proprietà che i client non devono visualizzare.
- Omettere alcune proprietà per ridurre le dimensioni del payload.
- Appiattire gli oggetti grafici che contengono oggetti annidati. Gli oggetti grafici appiattiti possono essere più pratici per i client.
Per illustrare l'approccio DTO, aggiornare la TodoItem
classe in modo da includere un campo segreto:
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
public string Secret { get; set; }
}
}
Il campo segreto deve essere nascosto da questa app, ma un'app amministrativa potrebbe scegliere di esporla.
Verificare che sia possibile pubblicare e ottenere il campo segreto.
Creare un modello DTO:
public class TodoItemDTO
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
Aggiornare per TodoItemsController
usare TodoItemDTO
:
// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
if (id != todoItemDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoItemDTO.Name;
todoItem.IsComplete = todoItemDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> CreateTodoItem(TodoItemDTO todoItemDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id) =>
_context.TodoItems.Any(e => e.Id == id);
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
Verificare che non sia possibile pubblicare o ottenere il campo segreto.
Chiamare l'API Web con JavaScript
Vedere Esercitazione: Chiamare un'API Web ASP.NET Core con JavaScript.
Aggiungere il supporto per l'autenticazione a un'API Web
ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web core ASP.NET. Per proteggere le API Web e i contratti a pagina singola, usare una delle opzioni seguenti:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server è un framework OpenID Connessione 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).
Pubblicare in Azure
Per informazioni sulla distribuzione in Azure, vedere Avvio rapido: Distribuire un'app Web ASP.NET.
Risorse aggiuntive
Visualizzare o scaricare il codice di esempio per questa esercitazione. Vedere come scaricare un esempio.
Per ulteriori informazioni, vedi le seguenti risorse:
- Creare API Web con ASP.NET Core
- Esercitazione: Creare un'API minima con ASP.NET Core
- Documentazione delle API Web ASP.NET Core con Swagger/OpenAPI
- Razor Pagine con Entity Framework Core in ASP.NET Core - Esercitazione 1 di 8
- Routing alle azioni del controller in ASP.NET Core
- Tipi restituiti dall'azione del controller nell'API Web ASP.NET Core
- Distribuire le app ASP.NET Core in Servizio app di Azure
- Ospitare e distribuire ASP.NET Core
- Creare un'API Web con ASP.NET Core
Questa esercitazione illustra le nozioni di base per la creazione di un'API Web basata su controller che usa un database. Un altro approccio alla creazione di API in ASP.NET Core consiste nel creare API minime. Per informazioni sulla scelta tra API minime e API basate su controller, vedere Panoramica delle API. Per un'esercitazione sulla creazione di un'API minima, vedere Esercitazione: Creare un'API minima con ASP.NET Core.
In questa esercitazione apprenderai a:
- Creare un progetto di API Web.
- Aggiungere una classe modello e un contesto di database.
- Eseguire lo scaffolding di un controller con i metodi CRUD.
- Configurare il routing, i percorsi URL e i valori restituiti.
- Chiamare l'API Web con Postman.
Al termine si avrà un'API Web che può gestire gli elementi di tipo "attività" archiviati in un database.
Panoramica
Questa esercitazione consente di creare l'API seguente:
API | Descrizione | Testo della richiesta | Corpo della risposta |
---|---|---|---|
GET /api/todoitems |
Ottiene tutti gli elementi attività | None | Matrice di elementi attività |
GET /api/todoitems/{id} |
Ottiene un elemento in base all'ID | None | Elemento attività |
POST /api/todoitems |
Aggiunge un nuovo elemento | Elemento attività | Elemento attività |
PUT /api/todoitems/{id} |
Aggiorna un elemento esistente | Elemento attività | None |
DELETE /api/todoitems/{id} |
Elimina un elemento | None | None |
Il diagramma seguente visualizza la struttura dell'app.
Prerequisiti
- Visual Studio 2019 16.4 o versione successiva con il carico di lavoro Sviluppo ASP.NET e Web
- .NET Core 3.1 SDK
Creare un progetto Web
- Scegliere Nuovo>Progetto dal menu File.
- Selezionare il modello Applicazione Web ASP.NET Core e fare clic su Avanti.
- Assegnare al progetto il nome TodoApi e fare clic su Crea.
- Nella finestra di dialogo Crea una nuova applicazione Web di ASP.NET Core verificare che siano selezionati .NET Core e ASP.NET Core 3.1. Selezionare il modello API e fare clic su Crea.
Nota
Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.
Testare l'API
Il modello di progetto crea un'API WeatherForecast
. Chiamare il metodo Get
da un browser per eseguire il test dell'app.
Premere CTRL+F5 per eseguire l'app. Visual Studio apre un browser e naviga all'indirizzo https://localhost:<port>/weatherforecast
, dove <port>
è un numero di porta selezionato a caso.
Se in una finestra di dialogo viene chiesto se considerare attendibile il certificato IIS Express, selezionare Sì. Nella finestra di dialogo Avviso di sicurezza successiva selezionare Sì.
JSON simile al seguente viene restituito:
[
{
"date": "2019-07-16T19:04:05.7257911-06:00",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2019-07-17T19:04:05.7258461-06:00",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2019-07-18T19:04:05.7258467-06:00",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2019-07-19T19:04:05.7258471-06:00",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2019-07-20T19:04:05.7258474-06:00",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Aggiungere una classe modello
Un modello è un set di classi che rappresentano i dati gestiti dall'app. Il modello per questa app è una classe TodoItem
singola.
In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto. Selezionare Aggiungi>Nuova cartella. Denominare la cartella
Models
.Fare clic con il pulsante destro del mouse sulla
Models
cartella e scegliere Aggiungi>classe. Assegnare alla classe il nome TodoItem e selezionare Aggiungi.Sostituire il codice del modello con il codice seguente:
public class TodoItem
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
La proprietà Id
funziona come chiave univoca in un database relazionale.
Le classi di modello possono essere usate in qualsiasi punto del progetto, ma la Models
cartella viene usata per convenzione.
Aggiungere un contesto di database
Il contesto di database è la classe principale che coordina le funzionalità di Entity Framework per un modello di dati. Questa classe viene creata mediante derivazione dalla classe Microsoft.EntityFrameworkCore.DbContext
.
Aggiungere i pacchetti NuGet di
- Scegliere NuGet Gestione pacchetti > Gestisci pacchetti NuGet per la soluzione dal menu Strumenti.
- Selezionare la scheda Sfoglia e quindi immettere Microsoft.EntityFrameworkCore.InMemory nella casella di ricerca.
- Selezionare Microsoft.EntityFrameworkCore.InMemory nel riquadro sinistro.
- Selezionare la casella di controllo Progetto nel riquadro destro e quindi selezionare Installa.
Aggiungere il contesto del database TodoContext
- Fare clic con il pulsante destro del mouse sulla
Models
cartella e scegliere Aggiungi>classe. Assegnare alla classe il nome TodoContext e fare clic su Aggiungi.
Immetti il codice seguente:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } } }
Registrare il contesto del database
In ASP.NET Core i servizi come il contesto del database devono essere registrati con il contenitore di inserimento delle dipendenze. Il contenitore rende disponibile il servizio ai controller.
Eseguire l'aggiornamento Startup.cs
con il codice evidenziato seguente:
// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;
namespace TodoApi
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Il codice precedente:
- Rimuove le dichiarazioni
using
inutilizzate. - Aggiunge il contesto del database al contenitore di inserimento delle dipendenze.
- Specifica che il contesto del database userà un database in memoria.
Eseguire lo scaffolding di un controller
Fare clic con il pulsante destro del mouse sulla
Controllers
cartella.Selezionare Aggiungi>New Scaffolded Item.
Selezionare Controller API con azioni, che usa Entity Framework e quindi selezionare Aggiungi.
Nella finestra di dialogo Add API Controller with actions, using Entity Framework (Aggiungi controller API con azioni, che usa Entity Framework):
- Selezionare TodoItem (TodoApi.Models) nella classe Model.
- Selezionare TodoContext (TodoApi.Models) nella classe Contesto dati.
- Selezionare Aggiungi.
Il codice generato:
- Contrassegna la classe con l'attributo
[ApiController]
. L'attributo indica che il controller risponde alle richieste di API Web. Per informazioni sui comportamenti specifici che l'attributo abilita, vedere Creare API Web con ASP.NET Core. - Usa l'inserimento delle dipendenze per inserire il contesto del database (
TodoContext
) nel controller. Il contesto di database viene usato in ognuno dei metodi CRUD nel controller.
I modelli ASP.NET Core per:
- I controller con visualizzazioni includono
[action]
nel modello di route. - I controller API non includono
[action]
nel modello di route.
Quando il [action]
token non è incluso nel modello di route, il nome dell'azione viene escluso dalla route. Ovvero, il nome del metodo associato dell'azione non viene usato nella route corrispondente.
Esaminare il metodo di creazione PostTodoItem
Sostituire l'istruzione return in PostTodoItem
per usare l'operatore nameof:
// POST: api/TodoItems
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
//return CreatedAtAction("PostTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(PostTodoItem), new { id = todoItem.Id }, todoItem);
}
Il codice precedente è un metodo HTTP POST, come indicato dall'attributo [HttpPost]
. Il metodo ottiene il valore dell'elemento attività dal corpo della richiesta HTTP.
Per altre informazioni, vedere Routing con attributi Http[verb].
Il metodo CreatedAtAction:
- Restituisce un codice di stato HTTP 201 in caso di esito positivo. HTTP 201 è la risposta standard per un metodo HTTP POST che crea una nuova risorsa nel server.
- Aggiunge un'intestazione Location alla risposta. L'intestazione
Location
specifica l'URI dell'elemento attività appena creato. Per altre informazioni, vedere 201 Created. - Fa riferimento all'azione
GetTodoItem
per creare l'URI dell'intestazioneLocation
. La parola chiavenameof
C# viene usata per evitare di impostare il nome dell'azione come hardcoded nella chiamata aCreatedAtAction
.
Installare Postman
Questa esercitazione usa Postman per testare l'API Web.
- Installare Postman
- Avviare l'app Web.
- Avviare Postman.
- Disabilitare la verifica del certificato SSL:
- Postman per Windows: Postman per File> di Windows Impostazioni (scheda Generale), disabilitare la verifica del certificato SSL.
- Postman per macOS: Postman per Windows Postman> Impostazioni (scheda Generale), disabilitare la verifica del certificato SSL.
Avviso
Riattivare la verifica dei certificati SSL al termine del test del controller.
Testare PostTodoItem con Postman
Creare una nuova richiesta.
Impostare il metodo HTTP su
POST
.Impostare l'URI su
https://localhost:<port>/api/todoitems
. Ad esempio:https://localhost:5001/api/todoitems
.Selezionare la scheda Corpo.
Selezionare il pulsante di opzione raw (non elaborato).
Impostare il tipo su JSON (application/json).
Nel corpo della richiesta immettere JSON per un elemento attività:
{ "name":"walk dog", "isComplete":true }
Selezionare Invia.
Testare l'URI dell'intestazione della posizione con Postman
Selezionare la scheda Headers (Intestazioni) nel riquadro Response (Risposta).
Copiare il valore dell'intestazione Location (Posizione):
Impostare il metodo HTTP su
GET
.Impostare l'URI su
https://localhost:<port>/api/todoitems/1
. Ad esempio:https://localhost:5001/api/todoitems/1
.Selezionare Invia.
Esaminare i metodi GET
Questi metodi implementano due metodi GET:
GET /api/todoitems
GET /api/todoitems/{id}
Testare l'app chiamando i due endpoint da un browser o da Postman. Ad esempio:
https://localhost:5001/api/todoitems
https://localhost:5001/api/todoitems/1
Una risposta simile alla seguente viene generata dalla chiamata a GetTodoItems
:
[
{
"id": 1,
"name": "Item1",
"isComplete": false
}
]
Testare Get con Postman
- Creare una nuova richiesta.
- Impostare il metodo HTTP su GET.
- Impostare l'URI della richiesta su
https://localhost:<port>/api/todoitems
. Ad esempio:https://localhost:5001/api/todoitems
. - Impostare Two pane view (Visualizzazione in due riquadri) in Postman.
- Selezionare Invia.
Questa app usa un database in memoria. Se l'app viene arrestata e avviata, la richiesta GET precedente non restituirà alcun dato. Se non vengono restituiti dati, eseguire POST per pubblicare i dati nell'app.
Routing e percorsi di URL
L'attributo [HttpGet]
indica un metodo che risponde a una richiesta HTTP GET. Il percorso dell'URL per ogni metodo viene costruito nel modo seguente:
Iniziare con la stringa di modello nell'attributo
Route
del controller:[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase { private readonly TodoContext _context; public TodoItemsController(TodoContext context) { _context = context; }
Sostituire
[controller]
con il nome del controller, ovvero, per convenzione, il nome della classe controller meno il suffisso "Controller". In questo esempio il nome della classe controller è TodoItemsController, quindi il nome del controller è "TodoItems". Il routing ASP.NET Core non fa distinzione tra maiuscole e minuscole.Se l'attributo
[HttpGet]
ha un modello di route, ad esempio[HttpGet("products")]
, aggiungerlo al percorso. In questo esempio non si usa un modello. Per altre informazioni, vedere Routing con attributi Http[verb].
Nel metodo GetTodoItem
seguente, "{id}"
è una variabile segnaposto per l'identificatore univoco dell'elemento attività. Quando GetTodoItem
viene richiamato, il valore di "{id}"
nell'URL viene fornito al metodo nel relativo id
parametro.
// GET: api/TodoItems/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
Valori restituiti
Il tipo restituito GetTodoItems
dei metodi e GetTodoItem
è Il tipo T> ActionResult<. ASP.NET Core serializza automaticamente l'oggetto in JSON e scrive JSON nel corpo del messaggio di risposta. Il codice di risposta per questo tipo restituito è 200, presupponendo che non esistano eccezioni non gestite. Le eccezioni non gestite vengono convertite in errori 5xx.
I tipi restituiti ActionResult
possono rappresentare un ampio intervallo di codici di stato HTTP. Ad esempio, GetTodoItem
può restituire due valori di stato diversi:
- Se nessun elemento corrisponde all'ID richiesto, il metodo restituisce un codice di errore 404 NotFound .
- In caso contrario, il metodo restituisce 200 con un corpo della JSrisposta ON. La restituzione di
item
risulta in una risposta HTTP 200.
Metodo PutTodoItem
Esaminare il metodo PutTodoItem
:
// PUT: api/TodoItems/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
if (id != todoItem.Id)
{
return BadRequest();
}
_context.Entry(todoItem).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TodoItemExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
PutTodoItem
è simile a PostTodoItem
ma usa la richiesta HTTP PUT. La risposta è 204 (No Content). In base alla specifica HTTP, una richiesta PUT richiede che il client invii l'intera entità aggiornata e non solo le modifiche. Per supportare gli aggiornamenti parziali, usare HTTP PATCH.
Se si riceve un errore chiamando PutTodoItem
, chiamare GET
per verificare che il database includa un elemento.
Testare il metodo PutTodoItem
Questo esempio usa un database in memoria che deve essere inizializzato ogni volta che l'app viene avviata. Deve esistere un elemento nel database prima di eseguire una chiamata PUT. Chiamare GET per assicurarsi che nel database sia presente un elemento prima di effettuare una chiamata PUT.
Aggiornare l'elemento attività con ID = 1 e impostarne il nome su "feed fish":
{
"id":1,
"name":"feed fish",
"isComplete":true
}
L'immagine seguente visualizza l'aggiornamento di Postman:
Metodo DeleteTodoItem
Esaminare il metodo DeleteTodoItem
:
// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<ActionResult<TodoItem>> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return todoItem;
}
Testare il metodo DeleteTodoItem
Usare Postman per eliminare un elemento attività:
- Impostare il metodo su
DELETE
. - Impostare l'URI dell'oggetto da eliminare, ad esempio
https://localhost:5001/api/todoitems/1
. - Selezionare Invia.
Impedire l'over-post
Attualmente l'app di esempio espone l'intero TodoItem
oggetto. Le app di produzione limitano in genere i dati di input e restituiti usando un subset del modello. Esistono diversi motivi alla base di questa situazione e la sicurezza è una delle principali. Il subset di un modello viene in genere definito DTO (Data Transfer Object), modello di input o modello di visualizzazione. DTO viene usato in questo articolo.
Un DTO può essere usato per:
- Impedire l'over-post.
- Nascondere le proprietà che i client non devono visualizzare.
- Omettere alcune proprietà per ridurre le dimensioni del payload.
- Appiattire gli oggetti grafici che contengono oggetti annidati. Gli oggetti grafici appiattiti possono essere più pratici per i client.
Per illustrare l'approccio DTO, aggiornare la TodoItem
classe in modo da includere un campo segreto:
public class TodoItem
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
public string Secret { get; set; }
}
Il campo segreto deve essere nascosto da questa app, ma un'app amministrativa potrebbe scegliere di esporla.
Verificare che sia possibile pubblicare e ottenere il campo segreto.
Creare un modello DTO:
public class TodoItemDTO
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
Aggiornare per TodoItemsController
usare TodoItemDTO
:
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
return await _context.TodoItems
.Select(x => ItemToDTO(x))
.ToListAsync();
}
[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return ItemToDTO(todoItem);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
if (id != todoItemDTO.Id)
{
return BadRequest();
}
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
todoItem.Name = todoItemDTO.Name;
todoItem.IsComplete = todoItemDTO.IsComplete;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
{
return NotFound();
}
return NoContent();
}
[HttpPost]
public async Task<ActionResult<TodoItemDTO>> CreateTodoItem(TodoItemDTO todoItemDTO)
{
var todoItem = new TodoItem
{
IsComplete = todoItemDTO.IsComplete,
Name = todoItemDTO.Name
};
_context.TodoItems.Add(todoItem);
await _context.SaveChangesAsync();
return CreatedAtAction(
nameof(GetTodoItem),
new { id = todoItem.Id },
ItemToDTO(todoItem));
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
private bool TodoItemExists(long id) =>
_context.TodoItems.Any(e => e.Id == id);
private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
new TodoItemDTO
{
Id = todoItem.Id,
Name = todoItem.Name,
IsComplete = todoItem.IsComplete
};
}
Verificare che non sia possibile pubblicare o ottenere il campo segreto.
Chiamare l'API Web con JavaScript
Vedere Esercitazione: Chiamare un'API Web ASP.NET Core con JavaScript.
Aggiungere il supporto per l'autenticazione a un'API Web
ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web core ASP.NET. Per proteggere le API Web e i contratti a pagina singola, usare una delle opzioni seguenti:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server è un framework OpenID Connessione 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).
Pubblicare in Azure
Per informazioni sulla distribuzione in Azure, vedere Avvio rapido: Distribuire un'app Web ASP.NET.
Risorse aggiuntive
Visualizzare o scaricare il codice di esempio per questa esercitazione. Vedere come scaricare un esempio.
Per ulteriori informazioni, vedi le seguenti risorse:
- Creare API Web con ASP.NET Core
- Esercitazione: Creare un'API minima con ASP.NET Core
- Documentazione delle API Web ASP.NET Core con Swagger/OpenAPI
- Razor Pagine con Entity Framework Core in ASP.NET Core - Esercitazione 1 di 8
- Routing alle azioni del controller in ASP.NET Core
- Tipi restituiti dall'azione del controller nell'API Web ASP.NET Core
- Distribuire le app ASP.NET Core in Servizio app di Azure
- Ospitare e distribuire ASP.NET Core
- Creare un'API Web con ASP.NET Core
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per