Creación de una API Web con ASP.NET Core y MongoDBCreate a web API with ASP.NET Core and MongoDB

Por Pratik Khandelwal y Scott AddieBy Pratik Khandelwal and Scott Addie

En este tutorial se crea una API web que realiza operaciones de creación, lectura, actualización y eliminación (CRUD) en una base de datos NoSQL de MongoDB.This tutorial creates a web API that performs Create, Read, Update, and Delete (CRUD) operations on a MongoDB NoSQL database.

En este tutorial aprenderá a:In this tutorial, you learn how to:

  • Configurar MongoDBConfigure MongoDB
  • Crear una base de datos de MongoDBCreate a MongoDB database
  • Definir un esquema y una colección de MongoDBDefine a MongoDB collection and schema
  • Realizar operaciones de CRUD de MongoDB desde una API webPerform MongoDB CRUD operations from a web API
  • Personalizar la serialización de JSONCustomize JSON serialization

Vea o descargue el código de ejemplo (cómo descargarlo)View or download sample code (how to download)

Requisitos previosPrerequisites

Configurar MongoDBConfigure MongoDB

Si usa Windows, MongoDB está instalado en C:\Archivos de programa\MongoDB de forma predeterminada.If using Windows, MongoDB is installed at C:\Program Files\MongoDB by default. Agregue C:\Archivos de programa\MongoDB\Server\<número_versión>\bin a la variable de entorno Path.Add C:\Program Files\MongoDB\Server\<version_number>\bin to the Path environment variable. Este cambio permite el acceso a MongoDB desde cualquier lugar en el equipo de desarrollo.This change enables MongoDB access from anywhere on your development machine.

Use el Shell de mongo en los pasos siguientes para crear una base de datos, hacer colecciones y almacenar documentos.Use the mongo Shell in the following steps to create a database, make collections, and store documents. 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).For more information on mongo Shell commands, see Working with the mongo Shell.

  1. Elija un directorio en el equipo de desarrollo para almacenar los datos.Choose a directory on your development machine for storing the data. Por ejemplo, C:\BooksData en Windows.For example, C:\BooksData on Windows. Si no existe el directorio, créelo.Create the directory if it doesn't exist. El shell de mongo no crea nuevos directorios.The mongo Shell doesn't create new directories.

  2. Abra un shell de comandos.Open a command shell. Ejecute el comando siguiente para conectarse a MongoDB en el puerto predeterminado 27017.Run the following command to connect to MongoDB on default port 27017. No olvide reemplazar <data_directory_path> por el directorio que eligió en el paso anterior.Remember to replace <data_directory_path> with the directory you chose in the previous step.

    mongod --dbpath <data_directory_path>
    
  3. Abra otra instancia del shell de comandos.Open another command shell instance. Conéctese a la base de datos de prueba de forma predeterminada ejecutando el comando siguiente:Connect to the default test database by running the following command:

    mongo
    
  4. Ejecute lo siguiente en un shell de comandos:Run the following in a command shell:

    use BookstoreDb
    

    Si aún no existe, se crea una base de datos denominada BookstoreDb.If it doesn't already exist, a database named BookstoreDb is created. Si la base de datos existe, su conexión se abre para las transacciones.If the database does exist, its connection is opened for transactions.

  5. Cree una colección Books con el comando siguiente:Create a Books collection using following command:

    db.createCollection('Books')
    

    Se muestra el siguiente resultado:The following result is displayed:

    { "ok" : 1 }
    
  6. Defina un esquema para la colección Books e inserte dos documentos con el comando siguiente:Define a schema for the Books collection and insert two documents using the following command:

    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:The following result is displayed:

    {
      "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.The ID's shown in this article will not match the IDs when you run this sample.

  7. Vea los documentos en la base de datos mediante el comando siguiente:View the documents in the database using the following command:

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

    Se muestra el siguiente resultado:The following result is displayed:

    {
      "_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 tipo ObjectId para cada documento.The schema adds an autogenerated _id property of type ObjectId for each document.

La base de datos está lista.The database is ready. Puede empezar a crear la API web de ASP.NET Core.You can start creating the ASP.NET Core web API.

Creación de un proyecto de API web de ASP.NET CoreCreate the ASP.NET Core web API project

  1. Vaya a Archivo > Nuevo > Proyecto.Go to File > New > Project.

  2. Seleccione el tipo de proyecto Aplicación web de ASP.NET Core y, luego, Siguiente.Select the ASP.NET Core Web Application project type, and select Next.

  3. Denomine el proyecto BooksApi y seleccione Crear.Name the project BooksApi, and select Create.

  4. Seleccione .NET Core como plataforma de destino y ASP.NET Core 3.0.Select the .NET Core target framework and ASP.NET Core 3.0. Seleccione la plantilla de proyecto API y, luego, Crear.Select the API project template, and select Create.

  5. Visite la galería de NuGet: MongoDB.Driver para determinar la última versión estable del controlador .NET para MongoDB.Visit the NuGet Gallery: MongoDB.Driver to determine the latest stable version of the .NET driver for MongoDB. En la ventana Consola del Administrador de paquetes, desplácese hasta la raíz del proyecto.In the Package Manager Console window, navigate to the project root. Ejecute el siguiente comando para instalar el controlador .NET para MongoDB:Run the following command to install the .NET driver for MongoDB:

    Install-Package MongoDB.Driver -Version {VERSION}
    

Adición de un modelo de entidadAdd an entity model

  1. Agregue un directorio Modelos a la raíz del proyecto.Add a Models directory to the project root.

  2. Agregue una clase Book al directorio Modelos con el código siguiente:Add a Book class to the Models directory with the following code:

    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 IdIn the preceding class, the Id property:

    • para asignar el objeto de Common Language Runtime (CLR) a la colección de MongoDB.Is required for mapping the Common Language Runtime (CLR) object to the MongoDB collection.
    • para anotarla con [BsonId] a fin de designarla como clave principal del documento.Is annotated with [BsonId] to designate this property as the document's primary key.
    • para anotarla con [BsonRepresentation(BsonType.ObjectId)] a fin de permitir que se pase el parámetro como tipo string en lugar de una estructura ObjectId.Is annotated with [BsonRepresentation(BsonType.ObjectId)] to allow passing the parameter as type string instead of an ObjectId structure. Mongo controla la conversión de string a ObjectId.Mongo handles the conversion from string to ObjectId.

    La propiedad BookName se anota con el atributo [BsonElement].The BookName property is annotated with the [BsonElement] attribute. El valor Name del atributo representa el nombre de propiedad en la colección de MongoDB.The attribute's value of Name represents the property name in the MongoDB collection.

Adición de un modelo configuraciónAdd a configuration model

  1. Agregue los siguientes valores de configuración de base de datos a appsettings.json:Add the following database configuration values to appsettings.json:

    {
      "BookstoreDatabaseSettings": {
        "BooksCollectionName": "Books",
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookstoreDb"
      },
      "Logging": {
        "IncludeScopes": false,
        "Debug": {
          "LogLevel": {
            "Default": "Warning"
          }
        },
        "Console": {
          "LogLevel": {
            "Default": "Warning"
          }
        }
      }
    }
    
  2. Agregue un archivo BookstoreDatabaseSettings.cs al directorio Models con el código siguiente:Add a BookstoreDatabaseSettings.cs file to the Models directory with the following code:

    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 propiedad BookstoreDatabaseSettings del archivo appsettings.json.The preceding BookstoreDatabaseSettings class is used to store the appsettings.json file's BookstoreDatabaseSettings property values. Los nombres de las propiedades de JSON y C# son iguales para facilitar el proceso de asignación.The JSON and C# property names are named identically to ease the mapping process.

  3. Agregue el código resaltado siguiente a Startup.ConfigureServices:Add the following highlighted code to 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:In the preceding code:

    • La instancia de configuración a la que la sección BookstoreDatabaseSettings del archivo appsettings.json enlaza está registrada en el contenedor de inserción de dependencias (DI).The configuration instance to which the appsettings.json file's BookstoreDatabaseSettings section binds is registered in the Dependency Injection (DI) container. Por ejemplo, una propiedad ConnectionString del objeto BookstoreDatabaseSettings se rellena con la propiedad BookstoreDatabaseSettings:ConnectionString en appsettings.json.For example, a BookstoreDatabaseSettings object's ConnectionString property is populated with the BookstoreDatabaseSettings:ConnectionString property in appsettings.json.
    • La interfaz IBookstoreDatabaseSettings se registra en la inserción de dependencias con una duración de servicio de tipo singleton.The IBookstoreDatabaseSettings interface is registered in DI with a singleton service lifetime. Cuando se inserta, la instancia de la interfaz se resuelve en un objeto BookstoreDatabaseSettings.When injected, the interface instance resolves to a BookstoreDatabaseSettings object.
  4. Agregue el código siguiente en la parte superior del archivo Startup.cs para resolver las referencias a BookstoreDatabaseSettings y IBookstoreDatabaseSettings:Add the following code to the top of Startup.cs to resolve the BookstoreDatabaseSettings and IBookstoreDatabaseSettings references:

    using BooksApi.Models;
    

Adición de un servicio de operaciones CRUDAdd a CRUD operations service

  1. Agregue un directorio Servicios a la raíz del proyecto.Add a Services directory to the project root.

  2. Agregue una clase BookService al directorio Servicios con el código siguiente:Add a BookService class to the Services directory with the following code:

    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.In the preceding code, an IBookstoreDatabaseSettings instance is retrieved from DI via constructor injection. Esta técnica proporciona acceso a los valores de configuración de appsettings.json que se agregaron en la sección Adición de un modelo de configuración.This technique provides access to the appsettings.json configuration values that were added in the Add a configuration model section.

  3. Agregue el código resaltado siguiente a Startup.ConfigureServices:Add the following highlighted code to 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.In the preceding code, the BookService class is registered with DI to support constructor injection in consuming classes. La duración de servicio de tipo singleton es la más adecuada porque BookService toma una dependencia directa sobre MongoClient.The singleton service lifetime is most appropriate because BookService takes a direct dependency on MongoClient. 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.Per the official Mongo Client reuse guidelines, MongoClient should be registered in DI with a singleton service lifetime.

  4. Agregue el código siguiente en la parte superior del archivo Startup.cs para resolver la referencia a BookService:Add the following code to the top of Startup.cs to resolve the BookService reference:

    using BooksApi.Services;
    

La claseBookService usa los miembros MongoDB.Driver siguientes para realizar operaciones CRUD en la base de datos:The BookService class uses the following MongoDB.Driver members to perform CRUD operations against the database:

  • MongoClient: lee la instancia del servidor para realizar operaciones de base de datos.MongoClient – Reads the server instance for performing database operations. Se proporciona la cadena de conexión de MongoDB al constructor de esta clase:The constructor of this class is provided the MongoDB connection string:

    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 realizar operaciones.IMongoDatabase – Represents the Mongo database for performing operations. 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.This tutorial uses the generic GetCollection<TDocument>(collection) method on the interface to gain access to data in a specific collection. Realice las operaciones CRUD en la colección después de llamar a este método.Perform CRUD operations against the collection after this method is called. En la llamada al método GetCollection<TDocument>(collection):In the GetCollection<TDocument>(collection) method call:

    • collection representa el nombre de la colección.collection represents the collection name.
    • TDocument representa el tipo de objeto CLR almacenado en la colección.TDocument represents the CLR object type stored in the collection.

GetCollection<TDocument>(collection) devuelve un objeto MongoCollection que representa la colección.GetCollection<TDocument>(collection) returns a MongoCollection object representing the collection. En este tutorial, se invocan los métodos siguientes en la colección:In this tutorial, the following methods are invoked on the collection:

  • DeleteOne: elimina un único documento que cumpla los criterios de búsqueda proporcionados.DeleteOne – Deletes a single document matching the provided search criteria.
  • Find<TDocument>: devuelve todos los documentos de la colección que cumplen los criterios de búsqueda indicados.Find<TDocument> – Returns all documents in the collection matching the provided search criteria.
  • InsertOne: inserta el objeto proporcionado como un nuevo documento en la colección.InsertOne – Inserts the provided object as a new document in the collection.
  • ReplaceOne: reemplaza un único documento que cumpla los criterios de búsqueda indicados por el objeto proporcionado.ReplaceOne – Replaces the single document matching the provided search criteria with the provided object.

Incorporación de un controladorAdd a controller

Agregue una clase BooksController al directorio Controladores con el código siguiente:Add a BooksController class to the Controllers directory with the following code:

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(book.Id);

            return NoContent();
        }
    }
}

El controlador de API web anterior:The preceding web API controller:

  • Usa la clase BookService para realizar operaciones CRUD.Uses the BookService class to perform CRUD operations.
  • Contiene métodos de acción para admitir las solicitudes GET, POST, PUT y DELETE de HTTP.Contains action methods to support GET, POST, PUT, and DELETE HTTP requests.
  • Llama a CreatedAtRoute en el método de acción Create para devolver una respuesta HTTP 201.Calls CreatedAtRoute in the Create action method to return an HTTP 201 response. El código de estado 201 es la respuesta estándar para un método HTTP POST que crea un recurso en el servidor.Status code 201 is the standard response for an HTTP POST method that creates a new resource on the server. CreatedAtRoute también agrega un encabezado Location a la respuesta.CreatedAtRoute also adds a Location header to the response. El encabezado Location especifica el identificador URI del libro recién creado.The Location header specifies the URI of the newly created book.

Prueba de la API webTest the web API

  1. Compile y ejecute la aplicación.Build and run the app.

  2. Vaya a http://localhost:<port>/api/books para probar el método de acción Get sin parámetros del controlador.Navigate to http://localhost:<port>/api/books to test the controller's parameterless Get action method. Se muestra la siguiente respuesta JSON:The following JSON response is displayed:

    [
      {
        "id":"5bfd996f7b8e48dc15ff215d",
        "bookName":"Design Patterns",
        "price":54.93,
        "category":"Computers",
        "author":"Ralph Johnson"
      },
      {
        "id":"5bfd996f7b8e48dc15ff215e",
        "bookName":"Clean Code",
        "price":43.15,
        "category":"Computers",
        "author":"Robert C. Martin"
      }
    ]
    
  3. Vaya a http://localhost:<port>/api/books/{id here} para probar el método de acción Get sobrecargado del controlador.Navigate to http://localhost:<port>/api/books/{id here} to test the controller's overloaded Get action method. Se muestra la siguiente respuesta JSON:The following JSON response is displayed:

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

Configuración de las opciones de serialización de JSONConfigure JSON serialization options

Hay dos detalles que cambiar sobre las respuestas JSON devueltas en la sección Prueba de la API web:There are two details to change about the JSON responses returned in the Test the web API section:

  • 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.The property names' default camel casing should be changed to match the Pascal casing of the CLR object's property names.
  • La propiedad bookName se debe devolver como Name.The bookName property should be returned as Name.

Para satisfacer los requisitos anteriores, realice los cambios siguientes:To satisfy the preceding requirements, make the following changes:

  1. JSON.NET se ha quitado de la plataforma compartida de ASP.NET.JSON.NET has been removed from ASP.NET shared framework. Agregue una referencia de paquete a Microsoft.AspNetCore.Mvc.NewtonsoftJson.Add a package reference to Microsoft.AspNetCore.Mvc.NewtonsoftJson.

  2. En Startup.ConfigureServices, cambie el código resaltado siguiente en la llamada al método AddControllers:In Startup.ConfigureServices, chain the following highlighted code on to the AddControllers method call:

    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.With the preceding change, property names in the web API's serialized JSON response match their corresponding property names in the CLR object type. Por ejemplo, la propiedad Author de la clase Book se serializa como Author.For example, the Book class's Author property serializes as Author.

  3. En Models/Book.cs, anote la propiedad BookName con el atributo [JsonProperty] siguiente:In Models/Book.cs, annotate the BookName property with the following [JsonProperty] attribute:

    [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.The [JsonProperty] attribute's value of Name represents the property name in the web API's serialized JSON response.

  4. Agregue el código siguiente en la parte superior del archivo Models/Book.cs para resolver la referencia al atributo [JsonProperty]:Add the following code to the top of Models/Book.cs to resolve the [JsonProperty] attribute reference:

    using Newtonsoft.Json;
    
  5. Repita los pasos definidos en la sección Prueba de la API web.Repeat the steps defined in the Test the web API section. Observe la diferencia en los nombres de propiedad JSON.Notice the difference in JSON property names.

En este tutorial se crea una API web que realiza operaciones de creación, lectura, actualización y eliminación (CRUD) en una base de datos NoSQL de MongoDB.This tutorial creates a web API that performs Create, Read, Update, and Delete (CRUD) operations on a MongoDB NoSQL database.

En este tutorial aprenderá a:In this tutorial, you learn how to:

  • Configurar MongoDBConfigure MongoDB
  • Crear una base de datos de MongoDBCreate a MongoDB database
  • Definir un esquema y una colección de MongoDBDefine a MongoDB collection and schema
  • Realizar operaciones de CRUD de MongoDB desde una API webPerform MongoDB CRUD operations from a web API
  • Personalizar la serialización de JSONCustomize JSON serialization

Vea o descargue el código de ejemplo (cómo descargarlo)View or download sample code (how to download)

Requisitos previosPrerequisites

Configurar MongoDBConfigure MongoDB

Si usa Windows, MongoDB está instalado en C:\Archivos de programa\MongoDB de forma predeterminada.If using Windows, MongoDB is installed at C:\Program Files\MongoDB by default. Agregue C:\Archivos de programa\MongoDB\Server\<número_versión>\bin a la variable de entorno Path.Add C:\Program Files\MongoDB\Server\<version_number>\bin to the Path environment variable. Este cambio permite el acceso a MongoDB desde cualquier lugar en el equipo de desarrollo.This change enables MongoDB access from anywhere on your development machine.

Use el Shell de mongo en los pasos siguientes para crear una base de datos, hacer colecciones y almacenar documentos.Use the mongo Shell in the following steps to create a database, make collections, and store documents. 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).For more information on mongo Shell commands, see Working with the mongo Shell.

  1. Elija un directorio en el equipo de desarrollo para almacenar los datos.Choose a directory on your development machine for storing the data. Por ejemplo, C:\BooksData en Windows.For example, C:\BooksData on Windows. Si no existe el directorio, créelo.Create the directory if it doesn't exist. El shell de mongo no crea nuevos directorios.The mongo Shell doesn't create new directories.

  2. Abra un shell de comandos.Open a command shell. Ejecute el comando siguiente para conectarse a MongoDB en el puerto predeterminado 27017.Run the following command to connect to MongoDB on default port 27017. No olvide reemplazar <data_directory_path> por el directorio que eligió en el paso anterior.Remember to replace <data_directory_path> with the directory you chose in the previous step.

    mongod --dbpath <data_directory_path>
    
  3. Abra otra instancia del shell de comandos.Open another command shell instance. Conéctese a la base de datos de prueba de forma predeterminada ejecutando el comando siguiente:Connect to the default test database by running the following command:

    mongo
    
  4. Ejecute lo siguiente en un shell de comandos:Run the following in a command shell:

    use BookstoreDb
    

    Si aún no existe, se crea una base de datos denominada BookstoreDb.If it doesn't already exist, a database named BookstoreDb is created. Si la base de datos existe, su conexión se abre para las transacciones.If the database does exist, its connection is opened for transactions.

  5. Cree una colección Books con el comando siguiente:Create a Books collection using following command:

    db.createCollection('Books')
    

    Se muestra el siguiente resultado:The following result is displayed:

    { "ok" : 1 }
    
  6. Defina un esquema para la colección Books e inserte dos documentos con el comando siguiente:Define a schema for the Books collection and insert two documents using the following command:

    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:The following result is displayed:

    {
      "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.The ID's shown in this article will not match the IDs when you run this sample.

  7. Vea los documentos en la base de datos mediante el comando siguiente:View the documents in the database using the following command:

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

    Se muestra el siguiente resultado:The following result is displayed:

    {
      "_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 tipo ObjectId para cada documento.The schema adds an autogenerated _id property of type ObjectId for each document.

La base de datos está lista.The database is ready. Puede empezar a crear la API web de ASP.NET Core.You can start creating the ASP.NET Core web API.

Creación de un proyecto de API web de ASP.NET CoreCreate the ASP.NET Core web API project

  1. Vaya a Archivo > Nuevo > Proyecto.Go to File > New > Project.

  2. Seleccione el tipo de proyecto Aplicación web de ASP.NET Core y, luego, Siguiente.Select the ASP.NET Core Web Application project type, and select Next.

  3. Denomine el proyecto BooksApi y seleccione Crear.Name the project BooksApi, and select Create.

  4. Seleccione el marco de destino .NET Core y ASP.NET Core 2.2.Select the .NET Core target framework and ASP.NET Core 2.2. Seleccione la plantilla de proyecto API y, luego, Crear.Select the API project template, and select Create.

  5. Visite la galería de NuGet: MongoDB.Driver para determinar la última versión estable del controlador .NET para MongoDB.Visit the NuGet Gallery: MongoDB.Driver to determine the latest stable version of the .NET driver for MongoDB. En la ventana Consola del Administrador de paquetes, desplácese hasta la raíz del proyecto.In the Package Manager Console window, navigate to the project root. Ejecute el siguiente comando para instalar el controlador .NET para MongoDB:Run the following command to install the .NET driver for MongoDB:

    Install-Package MongoDB.Driver -Version {VERSION}
    

Adición de un modelo de entidadAdd an entity model

  1. Agregue un directorio Modelos a la raíz del proyecto.Add a Models directory to the project root.

  2. Agregue una clase Book al directorio Modelos con el código siguiente:Add a Book class to the Models directory with the following code:

    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 IdIn the preceding class, the Id property:

    • para asignar el objeto de Common Language Runtime (CLR) a la colección de MongoDB.Is required for mapping the Common Language Runtime (CLR) object to the MongoDB collection.
    • para anotarla con [BsonId] a fin de designarla como clave principal del documento.Is annotated with [BsonId] to designate this property as the document's primary key.
    • para anotarla con [BsonRepresentation(BsonType.ObjectId)] a fin de permitir que se pase el parámetro como tipo string en lugar de una estructura ObjectId.Is annotated with [BsonRepresentation(BsonType.ObjectId)] to allow passing the parameter as type string instead of an ObjectId structure. Mongo controla la conversión de string a ObjectId.Mongo handles the conversion from string to ObjectId.

    La propiedad BookName se anota con el atributo [BsonElement].The BookName property is annotated with the [BsonElement] attribute. El valor Name del atributo representa el nombre de propiedad en la colección de MongoDB.The attribute's value of Name represents the property name in the MongoDB collection.

Adición de un modelo configuraciónAdd a configuration model

  1. Agregue los siguientes valores de configuración de base de datos a appsettings.json:Add the following database configuration values to appsettings.json:

    {
      "BookstoreDatabaseSettings": {
        "BooksCollectionName": "Books",
        "ConnectionString": "mongodb://localhost:27017",
        "DatabaseName": "BookstoreDb"
      },
      "Logging": {
        "IncludeScopes": false,
        "Debug": {
          "LogLevel": {
            "Default": "Warning"
          }
        },
        "Console": {
          "LogLevel": {
            "Default": "Warning"
          }
        }
      }
    }
    
  2. Agregue un archivo BookstoreDatabaseSettings.cs al directorio Models con el código siguiente:Add a BookstoreDatabaseSettings.cs file to the Models directory with the following code:

    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 propiedad BookstoreDatabaseSettings del archivo appsettings.json.The preceding BookstoreDatabaseSettings class is used to store the appsettings.json file's BookstoreDatabaseSettings property values. Los nombres de las propiedades de JSON y C# son iguales para facilitar el proceso de asignación.The JSON and C# property names are named identically to ease the mapping process.

  3. Agregue el código resaltado siguiente a Startup.ConfigureServices:Add the following highlighted code to Startup.ConfigureServices:

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

    En el código anterior:In the preceding code:

    • La instancia de configuración a la que la sección BookstoreDatabaseSettings del archivo appsettings.json enlaza está registrada en el contenedor de inserción de dependencias (DI).The configuration instance to which the appsettings.json file's BookstoreDatabaseSettings section binds is registered in the Dependency Injection (DI) container. Por ejemplo, una propiedad ConnectionString del objeto BookstoreDatabaseSettings se rellena con la propiedad BookstoreDatabaseSettings:ConnectionString en appsettings.json.For example, a BookstoreDatabaseSettings object's ConnectionString property is populated with the BookstoreDatabaseSettings:ConnectionString property in appsettings.json.
    • La interfaz IBookstoreDatabaseSettings se registra en la inserción de dependencias con una duración de servicio de tipo singleton.The IBookstoreDatabaseSettings interface is registered in DI with a singleton service lifetime. Cuando se inserta, la instancia de la interfaz se resuelve en un objeto BookstoreDatabaseSettings.When injected, the interface instance resolves to a BookstoreDatabaseSettings object.
  4. Agregue el código siguiente en la parte superior del archivo Startup.cs para resolver las referencias a BookstoreDatabaseSettings y IBookstoreDatabaseSettings:Add the following code to the top of Startup.cs to resolve the BookstoreDatabaseSettings and IBookstoreDatabaseSettings references:

    using BooksApi.Models;
    

Adición de un servicio de operaciones CRUDAdd a CRUD operations service

  1. Agregue un directorio Servicios a la raíz del proyecto.Add a Services directory to the project root.

  2. Agregue una clase BookService al directorio Servicios con el código siguiente:Add a BookService class to the Services directory with the following code:

    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.In the preceding code, an IBookstoreDatabaseSettings instance is retrieved from DI via constructor injection. Esta técnica proporciona acceso a los valores de configuración de appsettings.json que se agregaron en la sección Adición de un modelo de configuración.This technique provides access to the appsettings.json configuration values that were added in the Add a configuration model section.

  3. Agregue el código resaltado siguiente a Startup.ConfigureServices:Add the following highlighted code to 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.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }
    

    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.In the preceding code, the BookService class is registered with DI to support constructor injection in consuming classes. La duración de servicio de tipo singleton es la más adecuada porque BookService toma una dependencia directa sobre MongoClient.The singleton service lifetime is most appropriate because BookService takes a direct dependency on MongoClient. 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.Per the official Mongo Client reuse guidelines, MongoClient should be registered in DI with a singleton service lifetime.

  4. Agregue el código siguiente en la parte superior del archivo Startup.cs para resolver la referencia a BookService:Add the following code to the top of Startup.cs to resolve the BookService reference:

    using BooksApi.Services;
    

La claseBookService usa los miembros MongoDB.Driver siguientes para realizar operaciones CRUD en la base de datos:The BookService class uses the following MongoDB.Driver members to perform CRUD operations against the database:

  • MongoClient: lee la instancia del servidor para realizar operaciones de base de datos.MongoClient – Reads the server instance for performing database operations. Se proporciona la cadena de conexión de MongoDB al constructor de esta clase:The constructor of this class is provided the MongoDB connection string:

    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 realizar operaciones.IMongoDatabase – Represents the Mongo database for performing operations. 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.This tutorial uses the generic GetCollection<TDocument>(collection) method on the interface to gain access to data in a specific collection. Realice las operaciones CRUD en la colección después de llamar a este método.Perform CRUD operations against the collection after this method is called. En la llamada al método GetCollection<TDocument>(collection):In the GetCollection<TDocument>(collection) method call:

    • collection representa el nombre de la colección.collection represents the collection name.
    • TDocument representa el tipo de objeto CLR almacenado en la colección.TDocument represents the CLR object type stored in the collection.

GetCollection<TDocument>(collection) devuelve un objeto MongoCollection que representa la colección.GetCollection<TDocument>(collection) returns a MongoCollection object representing the collection. En este tutorial, se invocan los métodos siguientes en la colección:In this tutorial, the following methods are invoked on the collection:

  • DeleteOne: elimina un único documento que cumpla los criterios de búsqueda proporcionados.DeleteOne – Deletes a single document matching the provided search criteria.
  • Find<TDocument>: devuelve todos los documentos de la colección que cumplen los criterios de búsqueda indicados.Find<TDocument> – Returns all documents in the collection matching the provided search criteria.
  • InsertOne: inserta el objeto proporcionado como un nuevo documento en la colección.InsertOne – Inserts the provided object as a new document in the collection.
  • ReplaceOne: reemplaza un único documento que cumpla los criterios de búsqueda indicados por el objeto proporcionado.ReplaceOne – Replaces the single document matching the provided search criteria with the provided object.

Incorporación de un controladorAdd a controller

Agregue una clase BooksController al directorio Controladores con el código siguiente:Add a BooksController class to the Controllers directory with the following code:

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(book.Id);

            return NoContent();
        }
    }
}

El controlador de API web anterior:The preceding web API controller:

  • Usa la clase BookService para realizar operaciones CRUD.Uses the BookService class to perform CRUD operations.
  • Contiene métodos de acción para admitir las solicitudes GET, POST, PUT y DELETE de HTTP.Contains action methods to support GET, POST, PUT, and DELETE HTTP requests.
  • Llama a CreatedAtRoute en el método de acción Create para devolver una respuesta HTTP 201.Calls CreatedAtRoute in the Create action method to return an HTTP 201 response. El código de estado 201 es la respuesta estándar para un método HTTP POST que crea un recurso en el servidor.Status code 201 is the standard response for an HTTP POST method that creates a new resource on the server. CreatedAtRoute también agrega un encabezado Location a la respuesta.CreatedAtRoute also adds a Location header to the response. El encabezado Location especifica el identificador URI del libro recién creado.The Location header specifies the URI of the newly created book.

Prueba de la API webTest the web API

  1. Compile y ejecute la aplicación.Build and run the app.

  2. Vaya a http://localhost:<port>/api/books para probar el método de acción Get sin parámetros del controlador.Navigate to http://localhost:<port>/api/books to test the controller's parameterless Get action method. Se muestra la siguiente respuesta JSON:The following JSON response is displayed:

    [
      {
        "id":"5bfd996f7b8e48dc15ff215d",
        "bookName":"Design Patterns",
        "price":54.93,
        "category":"Computers",
        "author":"Ralph Johnson"
      },
      {
        "id":"5bfd996f7b8e48dc15ff215e",
        "bookName":"Clean Code",
        "price":43.15,
        "category":"Computers",
        "author":"Robert C. Martin"
      }
    ]
    
  3. Vaya a http://localhost:<port>/api/books/{id here} para probar el método de acción Get sobrecargado del controlador.Navigate to http://localhost:<port>/api/books/{id here} to test the controller's overloaded Get action method. Se muestra la siguiente respuesta JSON:The following JSON response is displayed:

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

Configuración de las opciones de serialización de JSONConfigure JSON serialization options

Hay dos detalles que cambiar sobre las respuestas JSON devueltas en la sección Prueba de la API web:There are two details to change about the JSON responses returned in the Test the web API section:

  • 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.The property names' default camel casing should be changed to match the Pascal casing of the CLR object's property names.
  • La propiedad bookName se debe devolver como Name.The bookName property should be returned as Name.

Para satisfacer los requisitos anteriores, realice los cambios siguientes:To satisfy the preceding requirements, make the following changes:

  1. En Startup.ConfigureServices, cambie el código resaltado siguiente en la llamada al método AddMvc:In Startup.ConfigureServices, chain the following highlighted code on to the AddMvc method call:

    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.AddMvc()
                .AddJsonOptions(options => options.UseMemberCasing())
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }
    

    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.With the preceding change, property names in the web API's serialized JSON response match their corresponding property names in the CLR object type. Por ejemplo, la propiedad Author de la clase Book se serializa como Author.For example, the Book class's Author property serializes as Author.

  2. En Models/Book.cs, anote la propiedad BookName con el atributo [JsonProperty] siguiente:In Models/Book.cs, annotate the BookName property with the following [JsonProperty] attribute:

    [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.The [JsonProperty] attribute's value of Name represents the property name in the web API's serialized JSON response.

  3. Agregue el código siguiente en la parte superior del archivo Models/Book.cs para resolver la referencia al atributo [JsonProperty]:Add the following code to the top of Models/Book.cs to resolve the [JsonProperty] attribute reference:

    using Newtonsoft.Json;
    
  4. Repita los pasos definidos en la sección Prueba de la API web.Repeat the steps defined in the Test the web API section. Observe la diferencia en los nombres de propiedad JSON.Notice the difference in JSON property names.

Agregar compatibilidad con la autenticación a una API webAdd authentication support to a web API

La identidad de ASP.NET Core agrega la funcionalidad de inicio de sesión de la interfaz de usuario a las aplicaciones web de ASP.NET Core.ASP.NET Core Identity adds user interface (UI) login functionality to ASP.NET Core web apps. Para proteger las API web y las SPA, use una de las siguientes opciones:To secure web APIs and SPAs, use one of the following:

IdentityServer4 es un marco de OpenID Connect y OAuth 2.0 para ASP.NET Core.IdentityServer4 is an OpenID Connect and OAuth 2.0 framework for ASP.NET Core. IdentityServer4 permite la utilización de las siguientes características de seguridad:IdentityServer4 enables the following security features:

  • Autenticación como servicio (AaaS)Authentication as a Service (AaaS)
  • Inicio de sesión único (SSO) mediante varios tipos de aplicacionesSingle sign-on/off (SSO) over multiple application types
  • Control de acceso para APIAccess control for APIs
  • Federation GatewayFederation Gateway

Para obtener más información, vea Bienvenida a IdentityServer4.For more information, see Welcome to IdentityServer4.

Pasos siguientesNext steps

Para obtener más información sobre la creación de las API web de ASP.NET Core, consulte los siguientes recursos:For more information on building ASP.NET Core web APIs, see the following resources: