Creación de una API Web con ASP.NET Core y MongoDB
Nota:
Esta no es la versión más reciente de este artículo. Para la versión actual, consulta la versión .NET 8 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulta la Directiva de soporte técnico de .NET y .NET Core. Para la versión actual, consulta la versión .NET 8 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulte la versión .NET 8 de este artículo.
Por Pratik Khandelwal y Scott Addie
En este tutorial se crea una API web que ejecuta operaciones de creación, lectura, actualización y eliminación (CRUD) en una base de datos NoSQL de MongoDB.
En este tutorial aprenderá a:
- Configurar MongoDB
- Crear una base de datos de MongoDB
- Definir un esquema y una colección de MongoDB
- Realizar operaciones de CRUD de MongoDB desde una API web
- Personalizar la serialización de JSON
Requisitos previos
Visual Studio 2022 con la carga de trabajo de ASP.NET y desarrollo web
Configurar MongoDB
Habilite el acceso a MongoDB y al shell de MongoDB desde cualquier lugar en el equipo de desarrollo (Windows/Linux/macOS):
Descargue e instale el shell de MongoDB:
- macOS/Linux: elija un directorio para extraer el shell de MongoDB. Agregue la ruta de acceso resultante para
mongosh
a la variable de entornoPATH
. - Windows: el shell de MongoDB (mongosh.exe) se instala en C:\Users<usuario>\AppData\Local\Programs\mongosh. Agregue la ruta de acceso resultante para
mongosh.exe
a la variable de entornoPATH
.
- macOS/Linux: elija un directorio para extraer el shell de MongoDB. Agregue la ruta de acceso resultante para
Descargue e instale MongoDB:
- macOS/Linux: compruebe el directorio en el que se instaló MongoDB, normalmente en /usr/local/mongodb. Agregue la ruta de acceso resultante para
mongodb
a la variable de entornoPATH
. - Windows: MongoDB está instalado en C:\Archivos de programa\MongoDB de forma predeterminada. Agregue C:\Archivos de programa\MongoDB\Server<número_versión>\bin a la variable de entorno
PATH
.
- macOS/Linux: compruebe el directorio en el que se instaló MongoDB, normalmente en /usr/local/mongodb. Agregue la ruta de acceso resultante para
Elija un directorio de almacenamiento de datos: seleccione un directorio en el equipo de desarrollo para almacenar los datos. Si no existe el directorio, créelo. El shell de MongoDB no crea nuevos directorios:
- macOS/Linux: por ejemplo,
/usr/local/var/mongodb
. - Windows: por ejemplo,
C:\\BooksData
.
- macOS/Linux: por ejemplo,
En el shell de comandos del sistema operativo (no en el shell de MongoDB), use el siguiente comando para conectarse a MongoDB en el puerto predeterminado 27017. Reemplace
<data_directory_path>
por el directorio elegido en el paso anterior.mongod --dbpath <data_directory_path>
Use el shell de MongoDB instalado previamente en los pasos siguientes para crear una base de datos, hacer colecciones y almacenar documentos. Para más información sobre los comandos de shell de MongoDB, vea mongosh
.
Abra una instancia del shell de comandos de MongoDB; para ello, inicie
mongosh.exe
.En el shell de comandos, conéctese a la base de datos de prueba predeterminada ejecutando el comando siguiente:
mongosh
Ejecute el comando siguiente en el shell de comandos:
use BookStore
Se crea una base de datos denominada BookStore si aún no existe. Si la base de datos existe, su conexión se abre para las transacciones.
Cree una colección
Books
con el comando siguiente:db.createCollection('Books')
Se muestra el siguiente resultado:
{ "ok" : 1 }
Defina un esquema para la colección
Books
e inserte dos documentos con el comando siguiente:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
Se muestra un resultado similar al siguiente:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
Nota:
Los objetos
ObjectId
que se muestran en el resultado anterior no coincidirán con los que se muestran en el shell de comandos.Vea los documentos en la base de datos mediante el comando siguiente:
db.Books.find().pretty()
Se muestra un resultado similar al siguiente:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
El esquema agrega una propiedad
_id
generada automáticamente del tipoObjectId
para cada documento.
Creación de un proyecto de API web de ASP.NET Core
Vaya a Archivo>Nuevo>Proyecto.
Seleccione el tipo de proyecto API web de ASP.NET Core y, luego, Siguiente.
Denomine el proyecto BookStoreApi y seleccione Siguiente.
Seleccione el marco .NET 8.0 (compatibilidad a largo plazo) y, a continuación, Crear.
En la ventana Consola del Administrador de paquetes, desplácese hasta la raíz del proyecto. Ejecute el siguiente comando para instalar el controlador .NET para MongoDB:
Install-Package MongoDB.Driver
Adición de un modelo de entidad
Agregue un directorio Modelos a la raíz del proyecto.
Agregue una clase
Book
al directorioBook
con el código siguiente:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
En la clase anterior, se requiere la propiedad
Id
:- para asignar el objeto de Common Language Runtime (CLR) a la colección de MongoDB.
- para anotarla con
[BsonId]
a fin de designarla como clave principal del documento. - para anotarla con
[BsonRepresentation(BsonType.ObjectId)]
a fin de permitir que se pase el parámetro como tipostring
en lugar de una estructura[BsonRepresentation(BsonType.ObjectId)]
. Mongo controla la conversión destring
aObjectId
.
La propiedad
BookName
se anota con el atributo[BsonElement]
. El valorName
del atributo representa el nombre de propiedad en la colección de MongoDB.
Adición de un modelo configuración
Agregue los siguientes valores de configuración de base de datos a
appsettings.json
:{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
Agregue una clase
BookStoreDatabaseSettings
al directorioBookStoreDatabaseSettings
con el código siguiente:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
La clase anterior
BookStoreDatabaseSettings
se utiliza para almacenar los valores de propiedadBookStoreDatabase
del archivoappsettings.json
. Los nombres de las propiedades de JSON y C# son iguales para facilitar el proceso de asignación.Agregue el código resaltado siguiente a
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
En el código anterior, la instancia de configuración a la que la sección
BookStoreDatabase
del archivoappsettings.json
enlaza está registrada en el contenedor de inserción de dependencias (DI). Por ejemplo, una propiedadConnectionString
del objetoBookStoreDatabaseSettings
se rellena con la propiedadBookStoreDatabase:ConnectionString
enappsettings.json
.Agregue el código siguiente en la parte superior del archivo
Program.cs
para resolver la referencia aBookStoreDatabaseSettings
:using BookStoreApi.Models;
Adición de un servicio de operaciones CRUD
Agregue un directorio Servicios a la raíz del proyecto.
Agregue una clase
BooksService
al directorioBooksService
con el código siguiente:using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
En el código anterior, se recuperó una instancia de
BookStoreDatabaseSettings
de la inserción de dependencias mediante la inserción de un constructor. Esta técnica proporciona acceso a los valores de configuración deappsettings.json
que se agregaron en la secciónappsettings.json
.Agregue el código resaltado siguiente a
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
En el código anterior, la clase
BooksService
se registra con inserción de dependencias para admitir la inserción del constructor en las clases de consumo. La duración de servicio de tipo singleton es la más adecuada porqueBooksService
toma una dependencia directa sobreMongoClient
. Según las instrucciones oficiales de reutilización de cliente Mongo,MongoClient
debe registrarse en la inserción de dependencias con una duración de servicio de tipo singleton.Agregue el código siguiente en la parte superior del archivo
Program.cs
para resolver la referencia aBooksService
:using BookStoreApi.Services;
La clase BooksService
usa los miembros MongoDB.Driver
siguientes para ejecutar operaciones CRUD en la base de datos:
MongoClient: lee la instancia del servidor para ejecutar operaciones de base de datos. Se proporciona la cadena de conexión de MongoDB al constructor de esta clase:
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase: representa la base de datos de Mongo para ejecutar operaciones. Este tutorial usa el método genérico GetCollection<TDocument>(collection) en la interfaz para tener acceso a los datos de una colección específica. Ejecute las operaciones CRUD en la colección después de llamar a este método. En la llamada al método
GetCollection<TDocument>(collection)
:collection
representa el nombre de la colección.TDocument
representa el tipo de objeto CLR almacenado en la colección.
GetCollection<TDocument>(collection)
devuelve un objeto GetCollection<TDocument>(collection)
que representa la colección. En este tutorial, se invocan los métodos siguientes en la colección:
- DeleteOneAsync: elimina un único documento que cumpla los criterios de búsqueda proporcionados.
- Find<TDocument>: devuelve todos los documentos de la colección que cumplen los criterios de búsqueda indicados.
- InsertOneAsync: inserta el objeto proporcionado como un nuevo documento en la colección.
- ReplaceOneAsync: reemplaza un único documento que cumpla los criterios de búsqueda indicados por el objeto proporcionado.
Incorporación de un controlador
Agregue una clase BooksController
al directorio BooksController
con el código siguiente:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
El controlador de API web anterior:
- Usa la clase
BooksService
para ejecutar operaciones CRUD. - Contiene métodos de acción para admitir las solicitudes GET, POST, PUT y DELETE de HTTP.
- Llama a CreatedAtAction en el método de acción
Create
para devolver una respuesta CreatedAtAction. El código de estado 201 es la respuesta estándar para un método HTTP POST que crea un recurso en el servidor.CreatedAtAction
también agrega un encabezadoLocation
a la respuesta. El encabezadoLocation
especifica el identificador URI del libro recién creado.
Prueba de la API web
Compile y ejecute la aplicación.
Vaya a
https://localhost:<port>/api/books
, donde<port>
es el número de puerto asignado automáticamente para la aplicación, para probar el método de acciónGet
sin parámetros del controlador y seleccione Probar>Ejecutar. Se muestra una respuesta JSON similar a la siguiente:[ { "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" }, { "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" } ]
Vaya a
https://localhost:<port>/api/books/{id here}
para probar el método de acciónGet
sobrecargado del controlador. Se muestra una respuesta JSON similar a la siguiente:{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
Configuración de las opciones de serialización de JSON
Hay dos detalles que cambiar sobre las respuestas JSON devueltas en la sección Prueba de la API web:
- Las mayúsculas y minúsculas Camel predeterminadas de los nombres de propiedad se deben cambiar para que coincidan con el uso de mayúsculas y minúsculas de Pascal de los nombres de propiedad del objeto CLR.
- La propiedad
bookName
se debe devolver comoName
.
Para satisfacer los requisitos anteriores, realice los cambios siguientes:
En
Program.cs
, cambie el código resaltado siguiente en la llamada al métodoAddControllers
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
Con el cambio anterior, los nombres de propiedad de la respuesta JSON serializada de la API web coinciden con sus nombres de propiedad correspondientes en el tipo de objeto CLR. Por ejemplo, la propiedad
Author
de la claseBook
se serializa comoAuthor
, en lugar deauthor
.En
Models/Book.cs
, anote la propiedadBookName
con el atributo[JsonPropertyName]
:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
El valor
Name
del atributo[JsonPropertyName]
representa el nombre de propiedad en la respuesta JSON serializada de la API web.Agregue el código siguiente en la parte superior de
Models/Book.cs
para resolver la referencia al atributo[JsonProperty]
:using System.Text.Json.Serialization;
Repita los pasos definidos en la sección Prueba de la API web. Observe la diferencia en los nombres de propiedad JSON.
Agregar compatibilidad con la autenticación a una API web
ASP.NET Core Identity agrega la funcionalidad de inicio de sesión de la interfaz de usuario (IU) a las aplicaciones web de ASP.NET Core. Para proteger las API web y las SPA, usa una de las siguientes opciones:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server es un marco de OpenID Connect y OAuth 2.0 para ASP.NET Core. Duende Identity Server permite las siguientes características de seguridad:
- Autenticación como servicio (AaaS)
- Inicio de sesión único (SSO) mediante varios tipos de aplicaciones
- Control de acceso para API
- Federation Gateway
Importante
Duende Software puede requerir que pagues una tarifa de licencia para el uso en producción de Duende Identity Server. Para obtener más información, consulta Migración de ASP.NET Core 5.0 a 6.0.
Para más información, consulte la documentación de Duende Identity Server (sitio web de Duende Software).
Recursos adicionales
En este tutorial se crea una API web que ejecuta operaciones de creación, lectura, actualización y eliminación (CRUD) en una base de datos NoSQL de MongoDB.
En este tutorial aprenderá a:
- Configurar MongoDB
- Crear una base de datos de MongoDB
- Definir un esquema y una colección de MongoDB
- Realizar operaciones de CRUD de MongoDB desde una API web
- Personalizar la serialización de JSON
Requisitos previos
Visual Studio 2022 con la carga de trabajo de ASP.NET y desarrollo web
Configurar MongoDB
Habilite el acceso a MongoDB y al shell de MongoDB desde cualquier lugar en el equipo de desarrollo:
En Windows, MongoDB está instalado en C:\Archivos de programa\MongoDB de forma predeterminada. Agregue C:\Archivos de programa\MongoDB\Server<número_versión>\bin a la variable de entorno
PATH
.Descargue el shell de MongoDB y elija un directorio para extraerlo. Agregue la ruta de acceso resultante para
mongosh.exe
a la variable de entornoPATH
.Elija un directorio en el equipo de desarrollo para almacenar los datos. Por ejemplo, C:\BooksData en Windows. Si no existe el directorio, créelo. El shell de mongo no crea nuevos directorios.
En el shell de comandos del sistema operativo (no en el shell de MongoDB), use el siguiente comando para conectarse a MongoDB en el puerto predeterminado 27017. Reemplace
<data_directory_path>
por el directorio elegido en el paso anterior.mongod --dbpath <data_directory_path>
Use el shell de MongoDB instalado previamente en los pasos siguientes para crear una base de datos, hacer colecciones y almacenar documentos. Para más información sobre los comandos de shell de MongoDB, vea mongosh
.
Abra una instancia del shell de comandos de MongoDB; para ello, inicie
mongosh.exe
.En el shell de comandos, conéctese a la base de datos de prueba predeterminada ejecutando el comando siguiente:
mongosh
Ejecute el comando siguiente en el shell de comandos:
use BookStore
Se crea una base de datos denominada BookStore si aún no existe. Si la base de datos existe, su conexión se abre para las transacciones.
Cree una colección
Books
con el comando siguiente:db.createCollection('Books')
Se muestra el siguiente resultado:
{ "ok" : 1 }
Defina un esquema para la colección
Books
e inserte dos documentos con el comando siguiente:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
Se muestra un resultado similar al siguiente:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
Nota:
Los objetos
ObjectId
que se muestran en el resultado anterior no coincidirán con los que se muestran en el shell de comandos.Vea los documentos en la base de datos mediante el comando siguiente:
db.Books.find().pretty()
Se muestra un resultado similar al siguiente:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
El esquema agrega una propiedad
_id
generada automáticamente del tipoObjectId
para cada documento.
Creación de un proyecto de API web de ASP.NET Core
Vaya a Archivo>Nuevo>Proyecto.
Seleccione el tipo de proyecto API web de ASP.NET Core y, luego, Siguiente.
Denomine el proyecto BookStoreApi y seleccione Siguiente.
Seleccione el marco .NET 7.0 (compatibilidad a plazo estándar) y, a continuación, Crear.
En el menú Herramientas, seleccione Administrador de paquetes NuGet>Consola del Administrador de paquetes.
En la ventana Consola del Administrador de paquetes, desplácese hasta la raíz del proyecto. Ejecute el siguiente comando para instalar el controlador .NET para MongoDB:
Install-Package MongoDB.Driver
Adición de un modelo de entidad
Agregue un directorio Modelos a la raíz del proyecto.
Agregue una clase
Book
al directorioBook
con el código siguiente:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
En la clase anterior, se requiere la propiedad
Id
:- para asignar el objeto de Common Language Runtime (CLR) a la colección de MongoDB.
- para anotarla con
[BsonId]
a fin de designarla como clave principal del documento. - para anotarla con
[BsonRepresentation(BsonType.ObjectId)]
a fin de permitir que se pase el parámetro como tipostring
en lugar de una estructura[BsonRepresentation(BsonType.ObjectId)]
. Mongo controla la conversión destring
aObjectId
.
La propiedad
BookName
se anota con el atributo[BsonElement]
. El valorName
del atributo representa el nombre de propiedad en la colección de MongoDB.
Adición de un modelo configuración
Agregue los siguientes valores de configuración de base de datos a
appsettings.json
:{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
Agregue una clase
BookStoreDatabaseSettings
al directorioBookStoreDatabaseSettings
con el código siguiente:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
La clase anterior
BookStoreDatabaseSettings
se utiliza para almacenar los valores de propiedadBookStoreDatabase
del archivoappsettings.json
. Los nombres de las propiedades de JSON y C# son iguales para facilitar el proceso de asignación.Agregue el código resaltado siguiente a
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
En el código anterior, la instancia de configuración a la que la sección
BookStoreDatabase
del archivoappsettings.json
enlaza está registrada en el contenedor de inserción de dependencias (DI). Por ejemplo, una propiedadConnectionString
del objetoBookStoreDatabaseSettings
se rellena con la propiedadBookStoreDatabase:ConnectionString
enappsettings.json
.Agregue el código siguiente en la parte superior del archivo
Program.cs
para resolver la referencia aBookStoreDatabaseSettings
:using BookStoreApi.Models;
Adición de un servicio de operaciones CRUD
Agregue un directorio Servicios a la raíz del proyecto.
Agregue una clase
BooksService
al directorioBooksService
con el código siguiente:using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
En el código anterior, se recuperó una instancia de
BookStoreDatabaseSettings
de la inserción de dependencias mediante la inserción de un constructor. Esta técnica proporciona acceso a los valores de configuración deappsettings.json
que se agregaron en la secciónappsettings.json
.Agregue el código resaltado siguiente a
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
En el código anterior, la clase
BooksService
se registra con inserción de dependencias para admitir la inserción del constructor en las clases de consumo. La duración de servicio de tipo singleton es la más adecuada porqueBooksService
toma una dependencia directa sobreMongoClient
. Según las instrucciones oficiales de reutilización de cliente Mongo,MongoClient
debe registrarse en la inserción de dependencias con una duración de servicio de tipo singleton.Agregue el código siguiente en la parte superior del archivo
Program.cs
para resolver la referencia aBooksService
:using BookStoreApi.Services;
La clase BooksService
usa los miembros MongoDB.Driver
siguientes para ejecutar operaciones CRUD en la base de datos:
MongoClient: lee la instancia del servidor para ejecutar operaciones de base de datos. Se proporciona la cadena de conexión de MongoDB al constructor de esta clase:
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase: representa la base de datos de Mongo para ejecutar operaciones. Este tutorial usa el método genérico GetCollection<TDocument>(collection) en la interfaz para tener acceso a los datos de una colección específica. Ejecute las operaciones CRUD en la colección después de llamar a este método. En la llamada al método
GetCollection<TDocument>(collection)
:collection
representa el nombre de la colección.TDocument
representa el tipo de objeto CLR almacenado en la colección.
GetCollection<TDocument>(collection)
devuelve un objeto GetCollection<TDocument>(collection)
que representa la colección. En este tutorial, se invocan los métodos siguientes en la colección:
- DeleteOneAsync: elimina un único documento que cumpla los criterios de búsqueda proporcionados.
- Find<TDocument>: devuelve todos los documentos de la colección que cumplen los criterios de búsqueda indicados.
- InsertOneAsync: inserta el objeto proporcionado como un nuevo documento en la colección.
- ReplaceOneAsync: reemplaza un único documento que cumpla los criterios de búsqueda indicados por el objeto proporcionado.
Incorporación de un controlador
Agregue una clase BooksController
al directorio BooksController
con el código siguiente:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
El controlador de API web anterior:
- Usa la clase
BooksService
para ejecutar operaciones CRUD. - Contiene métodos de acción para admitir las solicitudes GET, POST, PUT y DELETE de HTTP.
- Llama a CreatedAtAction en el método de acción
Create
para devolver una respuesta CreatedAtAction. El código de estado 201 es la respuesta estándar para un método HTTP POST que crea un recurso en el servidor.CreatedAtAction
también agrega un encabezadoLocation
a la respuesta. El encabezadoLocation
especifica el identificador URI del libro recién creado.
Prueba de la API web
Compile y ejecute la aplicación.
Vaya a
https://localhost:<port>/api/books
, donde<port>
es el número de puerto asignado automáticamente para la aplicación, para probar el método de acciónGet
sin parámetros del controlador. Se muestra una respuesta JSON similar a la siguiente:[ { "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" }, { "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" } ]
Vaya a
https://localhost:<port>/api/books/{id here}
para probar el método de acciónGet
sobrecargado del controlador. Se muestra una respuesta JSON similar a la siguiente:{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
Configuración de las opciones de serialización de JSON
Hay dos detalles que cambiar sobre las respuestas JSON devueltas en la sección Prueba de la API web:
- Las mayúsculas y minúsculas Camel predeterminadas de los nombres de propiedad se deben cambiar para que coincidan con el uso de mayúsculas y minúsculas de Pascal de los nombres de propiedad del objeto CLR.
- La propiedad
bookName
se debe devolver comoName
.
Para satisfacer los requisitos anteriores, realice los cambios siguientes:
En
Program.cs
, cambie el código resaltado siguiente en la llamada al métodoAddControllers
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
Con el cambio anterior, los nombres de propiedad de la respuesta JSON serializada de la API web coinciden con sus nombres de propiedad correspondientes en el tipo de objeto CLR. Por ejemplo, la propiedad
Author
de la claseBook
se serializa comoAuthor
, en lugar deauthor
.En
Models/Book.cs
, anote la propiedadBookName
con el atributo[JsonPropertyName]
:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
El valor
Name
del atributo[JsonPropertyName]
representa el nombre de propiedad en la respuesta JSON serializada de la API web.Agregue el código siguiente en la parte superior de
Models/Book.cs
para resolver la referencia al atributo[JsonProperty]
:using System.Text.Json.Serialization;
Repita los pasos definidos en la sección Prueba de la API web. Observe la diferencia en los nombres de propiedad JSON.
Agregar compatibilidad con la autenticación a una API web
ASP.NET Core Identity agrega la funcionalidad de inicio de sesión de la interfaz de usuario (IU) a las aplicaciones web de ASP.NET Core. Para proteger las API web y las SPA, usa una de las siguientes opciones:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server es un marco de OpenID Connect y OAuth 2.0 para ASP.NET Core. Duende Identity Server permite las siguientes características de seguridad:
- Autenticación como servicio (AaaS)
- Inicio de sesión único (SSO) mediante varios tipos de aplicaciones
- Control de acceso para API
- Federation Gateway
Importante
Duende Software puede requerir que pagues una tarifa de licencia para el uso en producción de Duende Identity Server. Para obtener más información, consulta Migración de ASP.NET Core 5.0 a 6.0.
Para más información, consulte la documentación de Duende Identity Server (sitio web de Duende Software).
Recursos adicionales
En este tutorial se crea una API web que ejecuta operaciones de creación, lectura, actualización y eliminación (CRUD) en una base de datos NoSQL de MongoDB.
En este tutorial aprenderá a:
- Configurar MongoDB
- Crear una base de datos de MongoDB
- Definir un esquema y una colección de MongoDB
- Realizar operaciones de CRUD de MongoDB desde una API web
- Personalizar la serialización de JSON
Requisitos previos
- Visual Studio 2022 con la carga de trabajo de ASP.NET y desarrollo web
- SDK de .NET 6.0
Configurar MongoDB
Habilite el acceso a MongoDB y al shell de MongoDB desde cualquier lugar en el equipo de desarrollo:
En Windows, MongoDB está instalado en C:\Archivos de programa\MongoDB de forma predeterminada. Agregue C:\Archivos de programa\MongoDB\Server<número_versión>\bin a la variable de entorno
PATH
.Descargue el shell de MongoDB y elija un directorio para extraerlo. Agregue la ruta de acceso resultante para
mongosh.exe
a la variable de entornoPATH
.Elija un directorio en el equipo de desarrollo para almacenar los datos. Por ejemplo, C:\BooksData en Windows. Si no existe el directorio, créelo. El shell de mongo no crea nuevos directorios.
En el shell de comandos del sistema operativo (no en el shell de MongoDB), use el siguiente comando para conectarse a MongoDB en el puerto predeterminado 27017. Reemplace
<data_directory_path>
por el directorio elegido en el paso anterior.mongod --dbpath <data_directory_path>
Use el shell de MongoDB instalado previamente en los pasos siguientes para crear una base de datos, hacer colecciones y almacenar documentos. Para más información sobre los comandos de shell de MongoDB, vea mongosh
.
Abra una instancia del shell de comandos de MongoDB; para ello, inicie
mongosh.exe
.En el shell de comandos, conéctese a la base de datos de prueba predeterminada ejecutando el comando siguiente:
mongosh
Ejecute el comando siguiente en el shell de comandos:
use BookStore
Se crea una base de datos denominada BookStore si aún no existe. Si la base de datos existe, su conexión se abre para las transacciones.
Cree una colección
Books
con el comando siguiente:db.createCollection('Books')
Se muestra el siguiente resultado:
{ "ok" : 1 }
Defina un esquema para la colección
Books
e inserte dos documentos con el comando siguiente:db.Books.insertMany([{ "Name": "Design Patterns", "Price": 54.93, "Category": "Computers", "Author": "Ralph Johnson" }, { "Name": "Clean Code", "Price": 43.15, "Category": "Computers","Author": "Robert C. Martin" }])
Se muestra un resultado similar al siguiente:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("61a6058e6c43f32854e51f51"), ObjectId("61a6058e6c43f32854e51f52") ] }
Nota:
Los objetos
ObjectId
que se muestran en el resultado anterior no coincidirán con los que se muestran en el shell de comandos.Vea los documentos en la base de datos mediante el comando siguiente:
db.Books.find().pretty()
Se muestra un resultado similar al siguiente:
{ "_id" : ObjectId("61a6058e6c43f32854e51f51"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("61a6058e6c43f32854e51f52"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
El esquema agrega una propiedad
_id
generada automáticamente del tipoObjectId
para cada documento.
Creación de un proyecto de API web de ASP.NET Core
Vaya a Archivo>Nuevo>Proyecto.
Seleccione el tipo de proyecto API web de ASP.NET Core y, luego, Siguiente.
Denomine el proyecto BookStoreApi y seleccione Siguiente.
Seleccione el marco .NET 6.0 (compatibilidad a largo plazo) y, a continuación, Crear.
En la ventana Consola del Administrador de paquetes, desplácese hasta la raíz del proyecto. Ejecute el siguiente comando para instalar el controlador .NET para MongoDB:
Install-Package MongoDB.Driver
Adición de un modelo de entidad
Agregue un directorio Modelos a la raíz del proyecto.
Agregue una clase
Book
al directorioBook
con el código siguiente:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BookStoreApi.Models; public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Author { get; set; } = null!; }
En la clase anterior, se requiere la propiedad
Id
:- para asignar el objeto de Common Language Runtime (CLR) a la colección de MongoDB.
- para anotarla con
[BsonId]
a fin de designarla como clave principal del documento. - para anotarla con
[BsonRepresentation(BsonType.ObjectId)]
a fin de permitir que se pase el parámetro como tipostring
en lugar de una estructura[BsonRepresentation(BsonType.ObjectId)]
. Mongo controla la conversión destring
aObjectId
.
La propiedad
BookName
se anota con el atributo[BsonElement]
. El valorName
del atributo representa el nombre de propiedad en la colección de MongoDB.
Adición de un modelo configuración
Agregue los siguientes valores de configuración de base de datos a
appsettings.json
:{ "BookStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookStore", "BooksCollectionName": "Books" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
Agregue una clase
BookStoreDatabaseSettings
al directorioBookStoreDatabaseSettings
con el código siguiente:namespace BookStoreApi.Models; public class BookStoreDatabaseSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string BooksCollectionName { get; set; } = null!; }
La clase anterior
BookStoreDatabaseSettings
se utiliza para almacenar los valores de propiedadBookStoreDatabase
del archivoappsettings.json
. Los nombres de las propiedades de JSON y C# son iguales para facilitar el proceso de asignación.Agregue el código resaltado siguiente a
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase"));
En el código anterior, la instancia de configuración a la que la sección
BookStoreDatabase
del archivoappsettings.json
enlaza está registrada en el contenedor de inserción de dependencias (DI). Por ejemplo, una propiedadConnectionString
del objetoBookStoreDatabaseSettings
se rellena con la propiedadBookStoreDatabase:ConnectionString
enappsettings.json
.Agregue el código siguiente en la parte superior del archivo
Program.cs
para resolver la referencia aBookStoreDatabaseSettings
:using BookStoreApi.Models;
Adición de un servicio de operaciones CRUD
Agregue un directorio Servicios a la raíz del proyecto.
Agregue una clase
BooksService
al directorioBooksService
con el código siguiente:using BookStoreApi.Models; using Microsoft.Extensions.Options; using MongoDB.Driver; namespace BookStoreApi.Services; public class BooksService { private readonly IMongoCollection<Book> _booksCollection; public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); } public async Task<List<Book>> GetAsync() => await _booksCollection.Find(_ => true).ToListAsync(); public async Task<Book?> GetAsync(string id) => await _booksCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Book newBook) => await _booksCollection.InsertOneAsync(newBook); public async Task UpdateAsync(string id, Book updatedBook) => await _booksCollection.ReplaceOneAsync(x => x.Id == id, updatedBook); public async Task RemoveAsync(string id) => await _booksCollection.DeleteOneAsync(x => x.Id == id); }
En el código anterior, se recuperó una instancia de
BookStoreDatabaseSettings
de la inserción de dependencias mediante la inserción de un constructor. Esta técnica proporciona acceso a los valores de configuración deappsettings.json
que se agregaron en la secciónappsettings.json
.Agregue el código resaltado siguiente a
Program.cs
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>();
En el código anterior, la clase
BooksService
se registra con inserción de dependencias para admitir la inserción del constructor en las clases de consumo. La duración de servicio de tipo singleton es la más adecuada porqueBooksService
toma una dependencia directa sobreMongoClient
. Según las instrucciones oficiales de reutilización de cliente Mongo,MongoClient
debe registrarse en la inserción de dependencias con una duración de servicio de tipo singleton.Agregue el código siguiente en la parte superior del archivo
Program.cs
para resolver la referencia aBooksService
:using BookStoreApi.Services;
La clase BooksService
usa los miembros MongoDB.Driver
siguientes para ejecutar operaciones CRUD en la base de datos:
MongoClient: lee la instancia del servidor para ejecutar operaciones de base de datos. Se proporciona la cadena de conexión de MongoDB al constructor de esta clase:
public BooksService( IOptions<BookStoreDatabaseSettings> bookStoreDatabaseSettings) { var mongoClient = new MongoClient( bookStoreDatabaseSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( bookStoreDatabaseSettings.Value.DatabaseName); _booksCollection = mongoDatabase.GetCollection<Book>( bookStoreDatabaseSettings.Value.BooksCollectionName); }
IMongoDatabase: representa la base de datos de Mongo para ejecutar operaciones. Este tutorial usa el método genérico GetCollection<TDocument>(collection) en la interfaz para tener acceso a los datos de una colección específica. Ejecute las operaciones CRUD en la colección después de llamar a este método. En la llamada al método
GetCollection<TDocument>(collection)
:collection
representa el nombre de la colección.TDocument
representa el tipo de objeto CLR almacenado en la colección.
GetCollection<TDocument>(collection)
devuelve un objeto GetCollection<TDocument>(collection)
que representa la colección. En este tutorial, se invocan los métodos siguientes en la colección:
- DeleteOneAsync: elimina un único documento que cumpla los criterios de búsqueda proporcionados.
- Find<TDocument>: devuelve todos los documentos de la colección que cumplen los criterios de búsqueda indicados.
- InsertOneAsync: inserta el objeto proporcionado como un nuevo documento en la colección.
- ReplaceOneAsync: reemplaza un único documento que cumpla los criterios de búsqueda indicados por el objeto proporcionado.
Incorporación de un controlador
Agregue una clase BooksController
al directorio BooksController
con el código siguiente:
using BookStoreApi.Models;
using BookStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace BookStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{
private readonly BooksService _booksService;
public BooksController(BooksService booksService) =>
_booksService = booksService;
[HttpGet]
public async Task<List<Book>> Get() =>
await _booksService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Book>> Get(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
return book;
}
[HttpPost]
public async Task<IActionResult> Post(Book newBook)
{
await _booksService.CreateAsync(newBook);
return CreatedAtAction(nameof(Get), new { id = newBook.Id }, newBook);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Book updatedBook)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
updatedBook.Id = book.Id;
await _booksService.UpdateAsync(id, updatedBook);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var book = await _booksService.GetAsync(id);
if (book is null)
{
return NotFound();
}
await _booksService.RemoveAsync(id);
return NoContent();
}
}
El controlador de API web anterior:
- Usa la clase
BooksService
para ejecutar operaciones CRUD. - Contiene métodos de acción para admitir las solicitudes GET, POST, PUT y DELETE de HTTP.
- Llama a CreatedAtAction en el método de acción
Create
para devolver una respuesta CreatedAtAction. El código de estado 201 es la respuesta estándar para un método HTTP POST que crea un recurso en el servidor.CreatedAtAction
también agrega un encabezadoLocation
a la respuesta. El encabezadoLocation
especifica el identificador URI del libro recién creado.
Prueba de la API web
Compile y ejecute la aplicación.
Vaya a
https://localhost:<port>/api/books
, donde<port>
es el número de puerto asignado automáticamente para la aplicación, para probar el método de acciónGet
sin parámetros del controlador. Se muestra una respuesta JSON similar a la siguiente:[ { "id": "61a6058e6c43f32854e51f51", "bookName": "Design Patterns", "price": 54.93, "category": "Computers", "author": "Ralph Johnson" }, { "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" } ]
Vaya a
https://localhost:<port>/api/books/{id here}
para probar el método de acciónGet
sobrecargado del controlador. Se muestra una respuesta JSON similar a la siguiente:{ "id": "61a6058e6c43f32854e51f52", "bookName": "Clean Code", "price": 43.15, "category": "Computers", "author": "Robert C. Martin" }
Configuración de las opciones de serialización de JSON
Hay dos detalles que cambiar sobre las respuestas JSON devueltas en la sección Prueba de la API web:
- Las mayúsculas y minúsculas Camel predeterminadas de los nombres de propiedad se deben cambiar para que coincidan con el uso de mayúsculas y minúsculas de Pascal de los nombres de propiedad del objeto CLR.
- La propiedad
bookName
se debe devolver comoName
.
Para satisfacer los requisitos anteriores, realice los cambios siguientes:
En
Program.cs
, cambie el código resaltado siguiente en la llamada al métodoAddControllers
:var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<BookStoreDatabaseSettings>( builder.Configuration.GetSection("BookStoreDatabase")); builder.Services.AddSingleton<BooksService>(); builder.Services.AddControllers() .AddJsonOptions( options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
Con el cambio anterior, los nombres de propiedad de la respuesta JSON serializada de la API web coinciden con sus nombres de propiedad correspondientes en el tipo de objeto CLR. Por ejemplo, la propiedad
Author
de la claseBook
se serializa comoAuthor
, en lugar deauthor
.En
Models/Book.cs
, anote la propiedadBookName
con el atributo[JsonPropertyName]
:[BsonElement("Name")] [JsonPropertyName("Name")] public string BookName { get; set; } = null!;
El valor
Name
del atributo[JsonPropertyName]
representa el nombre de propiedad en la respuesta JSON serializada de la API web.Agregue el código siguiente en la parte superior de
Models/Book.cs
para resolver la referencia al atributo[JsonProperty]
:using System.Text.Json.Serialization;
Repita los pasos definidos en la sección Prueba de la API web. Observe la diferencia en los nombres de propiedad JSON.
Agregar compatibilidad con la autenticación a una API web
ASP.NET Core Identity agrega la funcionalidad de inicio de sesión de la interfaz de usuario (IU) a las aplicaciones web de ASP.NET Core. Para proteger las API web y las SPA, usa una de las siguientes opciones:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende Identity Server
Duende Identity Server es un marco de OpenID Connect y OAuth 2.0 para ASP.NET Core. Duende Identity Server permite las siguientes características de seguridad:
- Autenticación como servicio (AaaS)
- Inicio de sesión único (SSO) mediante varios tipos de aplicaciones
- Control de acceso para API
- Federation Gateway
Importante
Duende Software puede requerir que pagues una tarifa de licencia para el uso en producción de Duende Identity Server. Para obtener más información, consulta Migración de ASP.NET Core 5.0 a 6.0.
Para más información, consulte la documentación de Duende Identity Server (sitio web de Duende Software).
Recursos adicionales
En este tutorial se crea una API web que ejecuta operaciones de creación, lectura, actualización y eliminación (CRUD) en una base de datos NoSQL de MongoDB.
En este tutorial aprenderá a:
- Configurar MongoDB
- Crear una base de datos de MongoDB
- Definir un esquema y una colección de MongoDB
- Realizar operaciones de CRUD de MongoDB desde una API web
- Personalizar la serialización de JSON
Vea o descargue el código de ejemplo (cómo descargarlo)
Requisitos previos
- .NET Core SDK 3.0 o posterior
- Visual Studio 2019 con la carga de trabajo ASP.NET y desarrollo web
- MongoDB
Configurar MongoDB
Si usa Windows, MongoDB está instalado en C:\Archivos de programa\MongoDB de forma predeterminada. Agregue C:\Archivos de programa\MongoDB\Server<número_versión>\bin a la variable de entorno Path
. Este cambio permite el acceso a MongoDB desde cualquier lugar en el equipo de desarrollo.
Use el Shell de mongo en los pasos siguientes para crear una base de datos, hacer colecciones y almacenar documentos. Para obtener más información sobre los comandos de Shell de mongo, consulte Working with the mongo Shell (Trabajo con el shell de Mongo).
Elija un directorio en el equipo de desarrollo para almacenar los datos. Por ejemplo, C:\BooksData en Windows. Si no existe el directorio, créelo. El shell de mongo no crea nuevos directorios.
Abra un shell de comandos. Ejecute el comando siguiente para conectarse a MongoDB en el puerto predeterminado 27017. No olvide reemplazar
<data_directory_path>
por el directorio que eligió en el paso anterior.mongod --dbpath <data_directory_path>
Abra otra instancia del shell de comandos. Conéctese a la base de datos de prueba de forma predeterminada ejecutando el comando siguiente:
mongo
Ejecute el comando siguiente en un shell de comandos:
use BookstoreDb
Se crea una base de datos denominada BookstoreDb si aún no existe. Si la base de datos existe, su conexión se abre para las transacciones.
Cree una colección
Books
con el comando siguiente:db.createCollection('Books')
Se muestra el siguiente resultado:
{ "ok" : 1 }
Defina un esquema para la colección
Books
e inserte dos documentos con el comando siguiente:db.Books.insertMany([{'Name':'Design Patterns','Price':54.93,'Category':'Computers','Author':'Ralph Johnson'}, {'Name':'Clean Code','Price':43.15,'Category':'Computers','Author':'Robert C. Martin'}])
Se muestra el siguiente resultado:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("5bfd996f7b8e48dc15ff215d"), ObjectId("5bfd996f7b8e48dc15ff215e") ] }
Nota:
Los identificadores que se muestran en este artículo no coinciden con los que se mostrarán cuando ejecute este ejemplo.
Vea los documentos en la base de datos mediante el comando siguiente:
db.Books.find({}).pretty()
Se muestra el siguiente resultado:
{ "_id" : ObjectId("5bfd996f7b8e48dc15ff215d"), "Name" : "Design Patterns", "Price" : 54.93, "Category" : "Computers", "Author" : "Ralph Johnson" } { "_id" : ObjectId("5bfd996f7b8e48dc15ff215e"), "Name" : "Clean Code", "Price" : 43.15, "Category" : "Computers", "Author" : "Robert C. Martin" }
El esquema agrega una propiedad
_id
generada automáticamente del tipoObjectId
para cada documento.
La base de datos está lista. Puede empezar a crear la API web de ASP.NET Core.
Creación de un proyecto de API web de ASP.NET Core
Vaya a Archivo>Nuevo>Proyecto.
Seleccione el tipo de proyecto Aplicación web de ASP.NET Core y, luego, Siguiente.
Denomine el proyecto BooksApi y seleccione Crear.
Seleccione .NET Core como plataforma de destino y ASP.NET Core 3.0. Seleccione la plantilla de proyecto API y, luego, Crear.
Visite la galería de NuGet: MongoDB.Driver para determinar la última versión estable del controlador .NET para MongoDB. En la ventana Consola del Administrador de paquetes, desplácese hasta la raíz del proyecto. Ejecute el siguiente comando para instalar el controlador .NET para MongoDB:
Install-Package MongoDB.Driver -Version {VERSION}
Adición de un modelo de entidad
Agregue un directorio Modelos a la raíz del proyecto.
Agregue una clase
Book
al directorioBook
con el código siguiente:using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace BooksApi.Models { public class Book { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } [BsonElement("Name")] public string BookName { get; set; } public decimal Price { get; set; } public string Category { get; set; } public string Author { get; set; } } }
En la clase anterior, se requiere la propiedad
Id
:- para asignar el objeto de Common Language Runtime (CLR) a la colección de MongoDB.
- para anotarla con
[BsonId]
a fin de designarla como clave principal del documento. - para anotarla con
[BsonRepresentation(BsonType.ObjectId)]
a fin de permitir que se pase el parámetro como tipostring
en lugar de una estructura[BsonRepresentation(BsonType.ObjectId)]
. Mongo controla la conversión destring
aObjectId
.
La propiedad
BookName
se anota con el atributo[BsonElement]
. El valorName
del atributo representa el nombre de propiedad en la colección de MongoDB.
Adición de un modelo configuración
Agregue los siguientes valores de configuración de base de datos a
appsettings.json
:{ "BookstoreDatabaseSettings": { "BooksCollectionName": "Books", "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "BookstoreDb" }, "Logging": { "IncludeScopes": false, "Debug": { "LogLevel": { "Default": "Warning" } }, "Console": { "LogLevel": { "Default": "Warning" } } } }
Agregue un archivo
BookstoreDatabaseSettings.cs
al directorio Models con el código siguiente:namespace BooksApi.Models { public class BookstoreDatabaseSettings : IBookstoreDatabaseSettings { public string BooksCollectionName { get; set; } public string ConnectionString { get; set; } public string DatabaseName { get; set; } } public interface IBookstoreDatabaseSettings { string BooksCollectionName { get; set; } string ConnectionString { get; set; } string DatabaseName { get; set; } } }
La clase anterior
BookstoreDatabaseSettings
se utiliza para almacenar los valores de propiedadBookstoreDatabaseSettings
del archivoappsettings.json
. Los nombres de las propiedades de JSON y C# son iguales para facilitar el proceso de asignación.Agregue el código resaltado siguiente a
Startup.ConfigureServices
:public void ConfigureServices(IServiceCollection services) { // requires using Microsoft.Extensions.Options services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddControllers(); }
En el código anterior:
- La instancia de configuración a la que la sección
BookstoreDatabaseSettings
del archivoappsettings.json
enlaza está registrada en el contenedor de inserción de dependencias (DI). Por ejemplo, una propiedadConnectionString
del objetoBookstoreDatabaseSettings
se rellena con la propiedadBookstoreDatabaseSettings:ConnectionString
enappsettings.json
. - La interfaz
IBookstoreDatabaseSettings
se registra en la inserción de dependencias con unaIBookstoreDatabaseSettings
de tipo singleton. Cuando se inserta, la instancia de la interfaz se resuelve en un objetoBookstoreDatabaseSettings
.
- La instancia de configuración a la que la sección
Agregue el código siguiente en la parte superior del archivo
Startup.cs
para resolver las referencia aBookstoreDatabaseSettings
yIBookstoreDatabaseSettings
:using BooksApi.Models;
Adición de un servicio de operaciones CRUD
Agregue un directorio Servicios a la raíz del proyecto.
Agregue una clase
BookService
al directorioBookService
con el código siguiente:using BooksApi.Models; using MongoDB.Driver; using System.Collections.Generic; using System.Linq; namespace BooksApi.Services { public class BookService { private readonly IMongoCollection<Book> _books; public BookService(IBookstoreDatabaseSettings settings) { var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName); } public List<Book> Get() => _books.Find(book => true).ToList(); public Book Get(string id) => _books.Find<Book>(book => book.Id == id).FirstOrDefault(); public Book Create(Book book) { _books.InsertOne(book); return book; } public void Update(string id, Book bookIn) => _books.ReplaceOne(book => book.Id == id, bookIn); public void Remove(Book bookIn) => _books.DeleteOne(book => book.Id == bookIn.Id); public void Remove(string id) => _books.DeleteOne(book => book.Id == id); } }
En el código anterior, se recuperó una instancia de
IBookstoreDatabaseSettings
de la inserción de dependencias mediante la inserción de un constructor. Esta técnica proporciona acceso a los valores de configuración deappsettings.json
que se agregaron en la secciónappsettings.json
.Agregue el código resaltado siguiente a
Startup.ConfigureServices
:public void ConfigureServices(IServiceCollection services) { services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddSingleton<BookService>(); services.AddControllers(); }
En el código anterior, la clase
BookService
se registra con inserción de dependencias para admitir la inserción del constructor en las clases de consumo. La duración de servicio de tipo singleton es la más adecuada porqueBookService
toma una dependencia directa sobreMongoClient
. Según las instrucciones oficiales de reutilización de cliente Mongo,MongoClient
debe registrarse en la inserción de dependencias con una duración de servicio de tipo singleton.Agregue el código siguiente en la parte superior del archivo
Startup.cs
para resolver la referencia aBookService
:using BooksApi.Services;
La clase BookService
usa los miembros MongoDB.Driver
siguientes para ejecutar operaciones CRUD en la base de datos:
MongoClient: lee la instancia del servidor para ejecutar operaciones de base de datos. Se proporciona la cadena de conexión de MongoDB al constructor de esta clase:
public BookService(IBookstoreDatabaseSettings settings) { var client = new MongoClient(settings.ConnectionString); var database = client.GetDatabase(settings.DatabaseName); _books = database.GetCollection<Book>(settings.BooksCollectionName); }
IMongoDatabase: representa la base de datos de Mongo para ejecutar operaciones. Este tutorial usa el método genérico GetCollection<TDocument>(collection) en la interfaz para tener acceso a los datos de una colección específica. Ejecute las operaciones CRUD en la colección después de llamar a este método. En la llamada al método
GetCollection<TDocument>(collection)
:collection
representa el nombre de la colección.TDocument
representa el tipo de objeto CLR almacenado en la colección.
GetCollection<TDocument>(collection)
devuelve un objeto GetCollection<TDocument>(collection)
que representa la colección. En este tutorial, se invocan los métodos siguientes en la colección:
- DeleteOne: elimina un único documento que cumple los criterios de búsqueda proporcionados.
- Find<TDocument>: devuelve todos los documentos de la colección que cumplen los criterios de búsqueda indicados.
- InsertOne: inserta el objeto proporcionado como un nuevo documento en la colección.
- ReplaceOne: reemplaza un único documento que cumple los criterios de búsqueda indicados por el objeto proporcionado.
Incorporación de un controlador
Agregue una clase BooksController
al directorio BooksController
con el código siguiente:
using BooksApi.Models;
using BooksApi.Services;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace BooksApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
private readonly BookService _bookService;
public BooksController(BookService bookService)
{
_bookService = bookService;
}
[HttpGet]
public ActionResult<List<Book>> Get() =>
_bookService.Get();
[HttpGet("{id:length(24)}", Name = "GetBook")]
public ActionResult<Book> Get(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
return book;
}
[HttpPost]
public ActionResult<Book> Create(Book book)
{
_bookService.Create(book);
return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
}
[HttpPut("{id:length(24)}")]
public IActionResult Update(string id, Book bookIn)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Update(id, bookIn);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public IActionResult Delete(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Remove(id);
return NoContent();
}
}
}
El controlador de API web anterior:
- Usa la clase
BookService
para ejecutar operaciones CRUD. - Contiene métodos de acción para admitir las solicitudes GET, POST, PUT y DELETE de HTTP.
- Llama a CreatedAtRoute en el método de acción
Create
para devolver una respuesta CreatedAtRoute. El código de estado 201 es la respuesta estándar para un método HTTP POST que crea un recurso en el servidor.CreatedAtRoute
también agrega un encabezadoLocation
a la respuesta. El encabezadoLocation
especifica el identificador URI del libro recién creado.
Prueba de la API web
Compile y ejecute la aplicación.
Vaya a
https://localhost:<port>/api/books
para probar el método de acciónGet
sin parámetros del controlador. Se muestra la siguiente respuesta JSON:[ { "id":"5bfd996f7b8e48dc15ff215d", "bookName":"Design Patterns", "price":54.93, "category":"Computers", "author":"Ralph Johnson" }, { "id":"5bfd996f7b8e48dc15ff215e", "bookName":"Clean Code", "price":43.15, "category":"Computers", "author":"Robert C. Martin" } ]
Vaya a
https://localhost:<port>/api/books/{id here}
para probar el método de acciónGet
sobrecargado del controlador. Se muestra la siguiente respuesta JSON:{ "id":"{ID}", "bookName":"Clean Code", "price":43.15, "category":"Computers", "author":"Robert C. Martin" }
Configuración de las opciones de serialización de JSON
Hay dos detalles que cambiar sobre las respuestas JSON devueltas en la sección Prueba de la API web:
- Las mayúsculas y minúsculas Camel predeterminadas de los nombres de propiedad se deben cambiar para que coincidan con el uso de mayúsculas y minúsculas de Pascal de los nombres de propiedad del objeto CLR.
- La propiedad
bookName
se debe devolver comoName
.
Para satisfacer los requisitos anteriores, realice los cambios siguientes:
JSON.NET se ha quitado de la plataforma compartida de ASP.NET. Agregue una referencia de paquete a
Microsoft.AspNetCore.Mvc.NewtonsoftJson
.En
Startup.ConfigureServices
, cambie el código resaltado siguiente en la llamada al métodoAddControllers
:public void ConfigureServices(IServiceCollection services) { services.Configure<BookstoreDatabaseSettings>( Configuration.GetSection(nameof(BookstoreDatabaseSettings))); services.AddSingleton<IBookstoreDatabaseSettings>(sp => sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value); services.AddSingleton<BookService>(); services.AddControllers() .AddNewtonsoftJson(options => options.UseMemberCasing()); }
Con el cambio anterior, los nombres de propiedad de la respuesta JSON serializada de la API web coinciden con sus nombres de propiedad correspondientes en el tipo de objeto CLR. Por ejemplo, la propiedad
Author
de la claseBook
se serializa comoAuthor
.En Models/Book.cs
Models/Book.cs
, anote la propiedadModels/Book.cs
con el atributo[JsonProperty]
siguiente:[BsonElement("Name")] [JsonProperty("Name")] public string BookName { get; set; }
El valor
Name
del atributo[JsonProperty]
representa el nombre de propiedad en la respuesta JSON serializada de la API web.Agregue el código siguiente en la parte superior de
Models/Book.cs
para resolver la referencia al atributo[JsonProperty]
:using Newtonsoft.Json;
Repita los pasos definidos en la sección Prueba de la API web. Observe la diferencia en los nombres de propiedad JSON.
Agregar compatibilidad con la autenticación a una API web
ASP.NET Core Identity agrega la funcionalidad de inicio de sesión de la interfaz de usuario (IU) a las aplicaciones web de ASP.NET Core. Para proteger las API web y las SPA, usa una de las siguientes opciones:
- Microsoft Entra ID
- Azure Active Directory B2C (Azure AD B2C)
- Duende IdentityServer. Duende IdentityServer es un producto de terceros.
Duende IdentityServer es un marco de OpenID Connect y OAuth 2.0 para ASP.NET Core. Duende IdentityServer habilita las siguientes características de seguridad:
- Autenticación como servicio (AaaS)
- Inicio de sesión único (SSO) mediante varios tipos de aplicaciones
- Control de acceso para API
- Federation Gateway
Para más información, consulta Información general de Duende IdentityServer.
Para más información sobre otros proveedores de autenticación, consulte Opciones de autenticación de OSS de la comunidad para ASP.NET Core.
Pasos siguientes
Para obtener más información sobre la creación de las API web de ASP.NET Core, consulte los siguientes recursos: