Esercitazione: Creare un'API Web basata su controller con ASP.NET Core
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 9 di questo articolo.
Di Tim Deschryver e Rick Anderson
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 |
Visualizza tutte le attività da fare | Nessuno | Elenco di attività da fare |
GET /api/todoitems/{id} |
Recupera un elemento tramite ID | None | Attività da fare |
POST /api/todoitems |
Aggiunge un nuovo elemento | Attività da fare | Attività da fare |
PUT /api/todoitems/{id} |
Aggiorna un elemento esistente | Attività da fare | None |
DELETE /api/todoitems/{id} |
Elimina un elemento | Nessuno | 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 API Web
- Dal menu File, scegliere Nuovo>Progetto.
- 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 il Framework sia .NET 9.0 (Supporto standard a termine).
- Verificare che la casella di controllo per Abilita supporto OpenAPI sia selezionata.
- Verificare che sia selezionata la casella di controllo per Usa controller (deselezionare l'uso delle API minime).
- Seleziona Crea.
Aggiungere un pacchetto NuGet
È necessario aggiungere un pacchetto NuGet per supportare il database usato in questa esercitazione.
- Dal menu Strumenti, selezionare Gestione pacchetti NuGet > Gestisci pacchetti NuGet per la soluzione.
- 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.
Eseguire il progetto
Il modello di progetto crea un'API WeatherForecast
con supporto per OpenAPI.
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, consultare l'errore del certificato Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
Visual Studio avvia una finestra del terminale e visualizza l'URL dell'app in esecuzione. L'API è ospitata in https://localhost:<port>
, dove <port>
è un numero di porta scelto in modo casuale impostato durante la creazione del progetto.
...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7260
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:7261
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
...
Ctrl+cliccare sull'URL HTTPS nella sezione di output per testare l'app-web in un browser. Non esiste alcun endpoint in https://localhost:<port>
, quindi il browser restituisce HTTP 404 Non trovato.
Aggiungere /weatherforecast
all'URL per testare l'API WeatherForecast.
Il browser visualizza JSON simile all'esempio seguente:
[
{
"date": "2025-07-16",
"temperatureC": 52,
"temperatureF": 125,
"summary": "Mild"
},
{
"date": "2025-07-17",
"temperatureC": 36,
"temperatureF": 96,
"summary": "Warm"
},
{
"date": "2025-07-18",
"temperatureC": 39,
"temperatureF": 102,
"summary": "Cool"
},
{
"date": "2025-07-19",
"temperatureC": 10,
"temperatureF": 49,
"summary": "Bracing"
},
{
"date": "2025-07-20",
"temperatureC": -1,
"temperatureF": 31,
"summary": "Chilly"
}
]
Testare il progetto
Questa esercitazione usa Endpoints Explorer e i file .http per testare l'API.
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 nel contenitore dell'iniezione di 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.AddOpenApi();
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseInMemoryDatabase("TodoList"));
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Il codice precedente:
- Aggiunge
using
direttive. - Aggiunge il contesto del database al contenitore di Dependency Injection.
- Specifica che il contesto del database userà un database in memoria.
Eseguire la creazione automatica 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 del modello.
- Selezionare TodoContext (TodoApi.Models) nella Classe di contesto dati.
- Selezionare Aggiungi.
Se l'operazione di scaffolding non riesce, selezionare Aggiungi per provare a eseguire lo scaffolding una seconda volta.
Questo passaggio aggiunge i pacchetti NuGet Microsoft.VisualStudio.Web.CodeGeneration.Design
e Microsoft.EntityFrameworkCore.Tools
al progetto.
Questi pacchetti sono necessari per lo scaffolding.
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. - Utilizza DI per iniettare 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 di restituzione 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("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), 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 ulteriori informazioni, vedere Routing degli attributi con 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 del nuovo elemento attività creato. Per altre informazioni, vedere 10.2.2 201 Created. - Fa riferimento all'azione
GetTodoItem
per creare l'URI dell'intestazioneLocation
. La parola chiave C#nameof
viene utilizzata per evitare di codificare staticamente il nome dell'azione nella chiamata aCreatedAtAction
.
Test di PostTodoItem
Selezionare Visualizza>Altre finestre>Esplora endpoint.
Fare clic con il pulsante destro del mouse sull'endpoint POST e scegliere Genera richiesta.
Viene creato un nuovo file nella cartella di progetto denominata
TodoApi.http
, con contenuto simile all'esempio seguente:@TodoApi_HostAddress = https://localhost:49738 POST {{TodoApi_HostAddress}}/api/todoitems Content-Type: application/json { //TodoItem } ###
- La prima riga crea una variabile usata per tutti gli endpoint.
- La riga successiva definisce una richiesta POST.
- Le righe successive alla richiesta POST definiscono le intestazioni e un segnaposto per il corpo della richiesta.
- La riga triple hashtag (
###
) è un delimitatore di richiesta: ciò che viene dopo è per una richiesta diversa.
La richiesta POST prevede un
TodoItem
. Per definire il todo, sostituire il commento//TodoItem
con il codice JSON seguente:{ "name": "walk dog", "isComplete": true }
Il file TodoApi.http dovrebbe ora essere simile all'esempio seguente, ma con il numero di porta:
@TodoApi_HostAddress = https://localhost:7260 Post {{TodoApi_HostAddress}}/api/todoitems Content-Type: application/json { "name": "walk dog", "isComplete": true } ###
Esegui l'app.
Selezionare il collegamento Invia richiesta sopra la riga della
POST
richiesta.La richiesta POST viene inviata all'app e la risposta viene visualizzata nel riquadro Risposta .
Testare l'URI del header di posizione
Testare l'app chiamando l'endpoint GET
da un browser o usando Esplora Endpoint. I passaggi seguenti sono relativi a Esplora Endpoints.
In Esplora endpoint fare clic con il pulsante destro del mouse sul primo endpoint GET e scegliere Genera richiesta.
Al file viene aggiunto il
TodoApi.http
contenuto seguente:GET {{TodoApi_HostAddress}}/api/todoitems ###
Selezionare il collegamento Invia richiesta sopra la nuova
GET
riga di richiesta.La richiesta GET viene inviata all'app e la risposta viene visualizzata nel riquadro Risposta .
Il corpo della risposta è simile al codice JSON seguente:
[ { "id": 1, "name": "walk dog", "isComplete": true } ]
In Esplora endpoint fare clic con il pulsante destro del mouse sull'endpoint
/api/todoitems/{id}
GET e scegliere Genera richiesta. Al file viene aggiunto ilTodoApi.http
contenuto seguente:@id=0 GET {{TodoApi_HostAddress}}/api/todoitems/{{id}} ###
Assegnare
{@id}
a1
anziché a0
.Selezionare il collegamento Invia richiesta che si trova sopra la nuova riga di richiesta GET.
La richiesta GET viene inviata all'app e la risposta viene visualizzata nel riquadro Risposta .
Il corpo della risposta è simile al codice JSON seguente:
{ "id": 1, "name": "walk dog", "isComplete": true }
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 di ASP.NET Core è insensibile alle maiuscole.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 ulteriori informazioni, vedere Routing degli attributi con Http[Verb].
Nel metodo GetTodoItem
seguente, "{id}"
è una variabile segnaposto per l'identificatore univoco dell'attività da fare. 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 dai metodi GetTodoItems
e GetTodoItem
è di tipo ActionResult<T>. ASP.NET Core serializza automaticamente l'oggetto su JSON e scrive il codice 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 di risposta JSON. Restituire
item
risulta 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.
Usare il metodo PUT
per aggiornare il TodoItem
con ID = 1 e impostarne il nome su "feed fish"
. Si noti che la risposta è HTTP 204 No Content
.
In Esplora endpoint fare clic con il pulsante destro del mouse sull'endpoint PUT e selezionare Genera richiesta.
Al file viene aggiunto il
TodoApi.http
contenuto seguente:PUT {{TodoApi_HostAddress}}/api/todoitems/{{id}} Content-Type: application/json { //TodoItem } ###
Nella riga della richiesta PUT sostituire
{{id}}
con1
.Sostituire il segnaposto
//TodoItem
con le righe seguenti:PUT {{TodoApi_HostAddress}}/api/todoitems/1 Content-Type: application/json { "id": 1, "name": "feed fish", "isComplete": false }
Seleziona il link Invia richiesta che si trova sopra la nuova riga di richiesta PUT.
La richiesta PUT viene inviata all'app e la risposta viene visualizzata nel riquadro Risposta . Il corpo della risposta è vuoto e il codice di stato è 204.
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 il metodo DELETE
per eliminare il TodoItem
con ID = 1. Si noti che la risposta è HTTP 204 No Content
.
In Esplora endpoint fare clic con il pulsante destro del mouse sull'endpoint DELETE e scegliere Genera richiesta.
Una richiesta DELETE viene aggiunta a
TodoApi.http
.Sostituire
{{id}}
nella riga di richiesta DELETE con1
. La richiesta DELETE dovrebbe essere simile all'esempio seguente:DELETE {{TodoApi_HostAddress}}/api/todoitems/{{id}} ###
Selezionare il collegamento Invia richiesta per la richiesta DELETE.
La richiesta DELETE viene inviata all'app e la risposta viene visualizzata nel riquadro Risposta . Il corpo della risposta è vuoto e il codice di stato è 204.
Testare con altri strumenti
Esistono molti altri strumenti che possono essere usati per testare le API Web, ad esempio:
Impedire un eccessivo numero di 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 la pubblicazione eccessiva.
- Nascondere le proprietà che i clienti non devono visualizzare.
- Omettere alcune proprietà per ridurre le dimensioni del payload.
- Appiattire i grafi di oggetti 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 postare e ottenere il campo segreto.
Creare un modello DTO in un file Models/TodoItemsDTO.cs:
namespace TodoApi.Models;
public class TodoItemDTO
{
public long Id { get; set; }
public string? Name { get; set; }
public bool IsComplete { get; set; }
}
Aggiorna il TodoItemsController
per utilizzare 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
};
}
Verifica che non sia possibile inviare 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 aziendali
Per indicazioni sulla creazione di un'app Web affidabile, sicura, efficiente, testabile e scalabile ASP.NET Core, vedere modelli di app Web Enterprise. È disponibile un'app Web di esempio completa di qualità di produzione che implementa i modelli.
Aggiungere il supporto per l'autenticazione a un'API Web
ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web ASP.NET Core. Per proteggere le API Web e le applicazioni a pagina singola, usare una delle opzioni seguenti:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server è un framework OpenID Connect e OAuth 2.0 per ASP.NET Core. Duende Identity Server abilita le funzionalità di sicurezza seguenti:
- Autenticazione come servizio (AaaS)
- Single Sign-On/off (SSO) su più tipi di applicazione
- Controllo di accesso per le API
- Gateway federativo
Importante
Duende Software potrebbe richiedere il pagamento di una tariffa di licenza per l'uso in produzione di Duende Identity Server. Per altre informazioni, vedere Eseguire la migrazione da ASP.NET Core 5.0 a 6.0.
Per altre informazioni, vedere la documentazione di Duende Server (sito Web duende Identity Software).
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. Vedi come scaricare.
Per ulteriori informazioni, vedi le seguenti risorse:
- Creare API Web con ASP.NET Core
- Esercitazione: Creare un'API minima con ASP.NET Core
- Usare i documenti OpenAPI generati
- 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 delle azioni del controller in ASP.NET Core
- Tipi restituiti dall'azione del controller nell'API Web ASP.NET Core
- Distribuzione di app ASP.NET Core in App Service 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:
Interfaccia di Programmazione delle Applicazioni (API) | Descrizione | Testo della richiesta | Corpo della risposta |
---|---|---|---|
GET /api/todoitems |
Visualizza tutte le attività da fare | Nessuno | Elenco di attività da fare |
GET /api/todoitems/{id} |
Recupera un elemento tramite ID | Nessuna | Attività da fare |
POST /api/todoitems |
Aggiunge un nuovo elemento | Attività da fare | Attività da fare |
PUT /api/todoitems/{id} |
Aggiorna un elemento esistente | Attività da fare | Nessuno |
DELETE /api/todoitems/{id} |
Elimina un elemento | Nessuno | 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
- Dal menu File, scegliere Nuovo>Progetto.
- 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:
- Confermare che il 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 per Abilita supporto OpenAPI sia selezionata.
- Seleziona Crea.
Aggiungere un pacchetto NuGet
È necessario aggiungere un pacchetto NuGet per supportare il database usato in questa esercitazione.
- Dal menu Strumenti, selezionare Gestione pacchetti NuGet > Gestisci pacchetti NuGet per la soluzione.
- 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, consultare l'errore del certificato Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
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 /swagger/index.html
. Selezionare GET>Prova>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 utilizzato per generare documentazione utile e guide per le API web. Questa esercitazione usa Swagger per testare l'app. Per ulteriori informazioni su Swagger, vedere la documentazione di ASP.NET Core Web API con Swagger/OpenAPI.
Copiare e incollare l'URL della richiesta nel browser:https://localhost:<port>/weatherforecast
Viene restituito json simile all'esempio seguente:
[
{
"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 nel contenitore dell'iniezione di 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 Dependency Injection.
- Specifica che il contesto del database userà un database in memoria.
Generare automaticamente 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 del modello.
- Selezionare TodoContext (TodoApi.Models) nella Classe di contesto dati.
- Selezionare Aggiungi.
Se l'operazione di scaffolding non riesce, selezionare Aggiungi per provare a effettuare il scaffolding di nuovo.
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. - Utilizza DI per iniettare 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 vedute 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 di restituzione 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("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), 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 ulteriori informazioni, vedere Routing degli attributi con 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 della lista di cose da fare appena creato. Per altre informazioni, vedere 10.2.2 201 Created. - Fa riferimento all'azione
GetTodoItem
per creare l'URI dell'intestazioneLocation
. La parola chiave C#nameof
viene utilizzata per evitare di codificare staticamente il nome dell'azione nella chiamata aCreatedAtAction
.
Test di 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 il JSON. ad esempio:
{ "name": "walk dog", "isComplete": true }
Selezionare Esegui
Testare l'URI dell'intestazione Location
Nella richiesta POST precedente, l'interfaccia utente di Swagger mostra l'intestazione di location sotto Intestazioni di risposta. Ad esempio: location: https://localhost:7260/api/TodoItems/1
. L'intestazione di localizzazione mostra l'URI della risorsa creata.
Per testare l'header di localizzazione:
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 interna. 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 di ASP.NET Core è insensibile alle maiuscole.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 ulteriori informazioni, vedere Routing degli attributi con Http[Verb].
Nel metodo GetTodoItem
seguente, "{id}"
è una variabile segnaposto per l'identificatore univoco dell'attività da fare. 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 dai metodi GetTodoItems
e GetTodoItem
è di tipo ActionResult<T>. ASP.NET Core serializza automaticamente l'oggetto su JSON e scrive il codice 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 di risposta JSON. Restituire
item
risulta 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:
- Esploratore di Endpoint di Visual Studio e file .http
- http-repl
-
curl. Swagger usa
curl
e mostra icurl
comandi inviati. - Fiddler
Per altre informazioni, vedi:
Impedire un eccessivo numero di 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 la pubblicazione eccessiva.
- Nascondere le proprietà che i clienti non devono visualizzare.
- Omettere alcune proprietà per ridurre le dimensioni del payload.
- Appiattire i grafi di oggetti 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 postare 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; }
}
Aggiorna il TodoItemsController
per utilizzare 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
};
}
Verifica che non sia possibile inviare 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 aziendali
Per indicazioni sulla creazione di un'app Web affidabile, sicura, efficiente, testabile e scalabile ASP.NET Core, vedere modelli di app Web Enterprise. È disponibile un'app Web di esempio completa di qualità di produzione che implementa i modelli.
Aggiungere il supporto per l'autenticazione a un'API Web
ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web ASP.NET Core. Per proteggere le API Web e le applicazioni a pagina singola, usare una delle opzioni seguenti:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server è un framework OpenID Connect e OAuth 2.0 per ASP.NET Core. Duende Identity Server abilita le funzionalità di sicurezza seguenti:
- Autenticazione come servizio (AaaS)
- Single Sign-On/off (SSO) su più tipi di applicazione
- Controllo di accesso per le API
- Gateway federativo
Importante
Duende Software potrebbe richiedere il pagamento di una tariffa di licenza per l'uso in produzione di Duende Identity Server. Per altre informazioni, vedere Eseguire la migrazione da ASP.NET Core 5.0 a 6.0.
Per altre informazioni, vedere la documentazione di Duende Server (sito Web duende Identity Software).
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. Vedi come scaricare.
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 delle azioni del controller in ASP.NET Core
- Tipi restituiti dall'azione del controller nell'API Web ASP.NET Core
- Distribuzione di app ASP.NET Core in App Service 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 |
Visualizza tutte le attività da fare | None | Elenco di attività da fare |
GET /api/todoitems/{id} |
Recupera un elemento tramite ID | None | Attività da fare |
POST /api/todoitems |
Aggiunge un nuovo elemento | Attività da fare | Attività da fare |
PUT /api/todoitems/{id} |
Aggiorna un elemento esistente | Attività da fare | Nessuno |
DELETE /api/todoitems/{id} |
Elimina un elemento | None | Nessuno |
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
- Dal menu File, scegliere Nuovo>Progetto.
- 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:
- Confermare che il 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 per Abilita supporto OpenAPI sia selezionata.
- Seleziona Crea.
Aggiungere un pacchetto NuGet
È necessario aggiungere un pacchetto NuGet per supportare il database usato in questa esercitazione.
- Dal menu Strumenti, selezionare Gestione pacchetti NuGet > Gestisci pacchetti NuGet per la soluzione.
- 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, consultare l'errore del certificato Firefox SEC_ERROR_INADEQUATE_KEY_USAGE.
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>Prova>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 utilizzato per generare documentazione utile e guide per le API web. Questa esercitazione usa Swagger per testare l'app. Per ulteriori informazioni su Swagger, vedere la documentazione di ASP.NET Core Web API con Swagger/OpenAPI.
Copiare e incollare l'URL della richiesta nel browser:https://localhost:<port>/weatherforecast
Viene restituito json simile all'esempio seguente:
[
{
"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 nel contenitore dell'iniezione di 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 Dependency Injection.
- Specifica che il contesto del database userà un database in memoria.
Creare automaticamente 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 del modello.
- Selezionare TodoContext (TodoApi.Models) nella Classe di 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. - Utilizza DI per iniettare 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 di restituzione 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("GetTodoItem", new { id = todoItem.Id }, todoItem);
return CreatedAtAction(nameof(GetTodoItem), 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 ulteriori informazioni, vedere Routing degli attributi con 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à creato. Per altre informazioni, vedere 10.2.2 201 Created. - Fa riferimento all'azione
GetTodoItem
per creare l'URI dell'intestazioneLocation
. La parola chiave C#nameof
viene utilizzata per evitare di codificare staticamente il nome dell'azione nella chiamata aCreatedAtAction
.
Test di 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 il JSON. ad esempio:
{ "name": "walk dog", "isComplete": true }
Selezionare Esegui
Testare l'URI dell'intestazione Location
Nella richiesta POST precedente, l'interfaccia utente di Swagger mostra l'intestazione di location sotto Intestazioni di risposta. Ad esempio: location: https://localhost:7260/api/TodoItems/1
. L'intestazione di localizzazione mostra l'URI della risorsa creata.
Per testare l'intestazione Location:
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 utilizza un database in memoria centrale. 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 di ASP.NET Core è insensibile alle maiuscole.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 ulteriori informazioni, vedere Routing degli attributi con Http[Verb].
Nel metodo GetTodoItem
seguente, "{id}"
è una variabile segnaposto per l'identificatore univoco dell'attività da fare. 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 dai metodi GetTodoItems
e GetTodoItem
è di tipo ActionResult<T>. ASP.NET Core serializza automaticamente l'oggetto su JSON e scrive il codice 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 di risposta JSON. Restituire
item
risulta 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:
- Esploratore di Endpoint di Visual Studio e file .http
- http-repl
-
curl. Swagger usa
curl
e mostra icurl
comandi inviati. - Fiddler
Per altre informazioni, vedi:
Impedire un eccessivo numero di 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 la pubblicazione eccessiva.
- Nascondere le proprietà che i clienti non devono visualizzare.
- Omettere alcune proprietà per ridurre le dimensioni del payload.
- Appiattire i grafi di oggetti 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 postare 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; }
}
Aggiorna il TodoItemsController
per utilizzare 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
};
}
Verifica che non sia possibile inviare 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 aziendali
Per indicazioni sulla creazione di un'app Web affidabile, sicura, efficiente, testabile e scalabile ASP.NET Core, vedere modelli di app Web Enterprise. È disponibile un'app Web di esempio completa di qualità di produzione che implementa i modelli.
Aggiungere il supporto per l'autenticazione a un'API Web
ASP.NET Core Identity aggiunge funzionalità di accesso dell'interfaccia utente alle app Web ASP.NET Core. Per proteggere le API Web e le applicazioni a pagina singola, usare una delle opzioni seguenti:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server è un framework OpenID Connect e OAuth 2.0 per ASP.NET Core. Duende Identity Server abilita le funzionalità di sicurezza seguenti:
- Autenticazione come servizio (AaaS)
- Single Sign-On/off (SSO) su più tipi di applicazione
- Controllo di accesso per le API
- Gateway federativo
Importante
Duende Software potrebbe richiedere il pagamento di una tariffa di licenza per l'uso in produzione di Duende Identity Server. Per altre informazioni, vedere Eseguire la migrazione da ASP.NET Core 5.0 a 6.0.
Per altre informazioni, vedere la documentazione di Duende Server (sito Web duende Identity Software).
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. Vedi come scaricare.
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 delle azioni del controller in ASP.NET Core
- Tipi restituiti dall'azione del controller nell'API Web ASP.NET Core
- Distribuzione di app ASP.NET Core in App Service di Azure
- Ospitare e distribuire ASP.NET Core
- Creare un'API Web con ASP.NET Core