Tutorial: Creación de una API web con ASP.NET CoreTutorial: Create a web API with ASP.NET Core

Por Rick Anderson y Mike WassonBy Rick Anderson and Mike Wasson

En este tutorial se enseñan los conceptos básicos de la compilación de una API web con ASP.NET Core.This tutorial teaches the basics of building a web API with ASP.NET Core.

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

  • Crear un proyecto de API web.Create a web API project.
  • Agregar una clase de modelo y un contexto de base de datos.Add a model class and a database context.
  • Aplicar scaffolding a un controlador con métodos CRUD.Scaffold a controller with CRUD methods.
  • Configurar el enrutamiento, las rutas de acceso URL y los valores devueltos.Configure routing, URL paths, and return values.
  • Llamar a la API web con Postman.Call the web API with Postman.

Al final, tendrá una API web que pueda administrar los elementos "to-do" almacenados en una base de datos.At the end, you have a web API that can manage "to-do" items stored in a database.

Información generalOverview

En este tutorial se crea la siguiente API:This tutorial creates the following API:

APIAPI DescripciónDescription Cuerpo de la solicitudRequest body Cuerpo de la respuestaResponse body
GET /api/TodoItemsGET /api/TodoItems Obtener todas las tareas pendientesGet all to-do items NingunaNone Matriz de tareas pendientesArray of to-do items
GET /api/TodoItems/{id}GET /api/TodoItems/{id} Obtener un elemento por identificadorGet an item by ID NoneNone Tarea pendienteTo-do item
POST /api/TodoItemsPOST /api/TodoItems Incorporación de un nuevo elementoAdd a new item Tarea pendienteTo-do item Tarea pendienteTo-do item
PUT /api/TodoItems/{id}PUT /api/TodoItems/{id} Actualizar un elemento existente  Update an existing item   Tarea pendienteTo-do item NoneNone
DELETE /api/TodoItems/{id}    DELETE /api/TodoItems/{id}     Eliminar un elemento    Delete an item     NoneNone NoneNone

En el diagrama siguiente, se muestra el diseño de la aplicación.The following diagram shows the design of the app.

El cliente está representado por un cuadro a la izquierda.

Requisitos previosPrerequisites

Creación de un proyecto webCreate a web project

  • En el menú Archivo, seleccione Nuevo > Proyecto.From the File menu, select New > Project.
  • Seleccione la plantilla Aplicación web ASP.NET Core y haga clic en Siguiente.Select the ASP.NET Core Web Application template and click Next.
  • Asigne al proyecto el nombre TodoApi y haga clic en Crear.Name the project TodoApi and click Create.
  • En el cuadro de diálogo Crear una aplicación web ASP.NET Core, confirme que las opciones .NET Core y ASP.NET Core 3.1 estén seleccionadas.In the Create a new ASP.NET Core Web Application dialog, confirm that .NET Core and ASP.NET Core 3.1 are selected. Seleccione la plantilla API y haga clic en Crear.Select the API template and click Create.

Cuadro de diálogo de nuevo proyecto de VS

Prueba de la APITest the API

La plantilla del proyecto crea una API WeatherForecast.The project template creates a WeatherForecast API. Llame al método Get desde un explorador para probar la aplicación.Call the Get method from a browser to test the app.

Presione Ctrl+F5 para ejecutar la aplicación.Press Ctrl+F5 to run the app. Visual Studio inicia un explorador y navega hasta https://localhost:<port>/WeatherForecast, donde <port> es un número de puerto elegido aleatoriamente.Visual Studio launches a browser and navigates to https://localhost:<port>/WeatherForecast, where <port> is a randomly chosen port number.

Si aparece un cuadro de diálogo en que se le pregunta si debe confiar en el certificado de IIS Express, seleccione .If you get a dialog box that asks if you should trust the IIS Express certificate, select Yes. En el cuadro de diálogo Advertencia de seguridad que aparece a continuación, seleccione .In the Security Warning dialog that appears next, select Yes.

Se devuelve un JSON similar al siguiente:JSON similar to the following is returned:

[
    {
        "date": "2019-07-16T19:04:05.7257911-06:00",
        "temperatureC": 52,
        "temperatureF": 125,
        "summary": "Mild"
    },
    {
        "date": "2019-07-17T19:04:05.7258461-06:00",
        "temperatureC": 36,
        "temperatureF": 96,
        "summary": "Warm"
    },
    {
        "date": "2019-07-18T19:04:05.7258467-06:00",
        "temperatureC": 39,
        "temperatureF": 102,
        "summary": "Cool"
    },
    {
        "date": "2019-07-19T19:04:05.7258471-06:00",
        "temperatureC": 10,
        "temperatureF": 49,
        "summary": "Bracing"
    },
    {
        "date": "2019-07-20T19:04:05.7258474-06:00",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Chilly"
    }
]

Incorporación de una clase de modeloAdd a model class

Un modelo es un conjunto de clases que representan los datos que la aplicación administra.A model is a set of classes that represent the data that the app manages. El modelo para esta aplicación es una clase TodoItem única.The model for this app is a single TodoItem class.

  • En el Explorador de soluciones, haga clic con el botón derecho en el proyecto.In Solution Explorer, right-click the project. Seleccione Agregar > Nueva carpeta.Select Add > New Folder. Asigne a la carpeta el nombre Models.Name the folder Models.

  • Haga clic con el botón derecho en la carpeta Models y seleccione Agregar > Clase.Right-click the Models folder and select Add > Class. Asigne a la clase el nombre TodoItem y seleccione Agregar.Name the class TodoItem and select Add.

  • Reemplace el código de plantilla por el código siguiente:Replace the template code with the following code:

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}

La propiedad Id funciona como clave única en una base de datos relacional.The Id property functions as the unique key in a relational database.

Las clases de modelo pueden ir en cualquier lugar del proyecto, pero convencionalmente e usa la carpeta Models.Model classes can go anywhere in the project, but the Models folder is used by convention.

Incorporación de un contexto de base de datosAdd a database context

El contexto de base de datos es la clase principal que coordina la funcionalidad de Entity Framework para un modelo de datos.The database context is the main class that coordinates Entity Framework functionality for a data model. Esta clase se crea derivándola de la clase Microsoft.EntityFrameworkCore.DbContext.This class is created by deriving from the Microsoft.EntityFrameworkCore.DbContext class.

Adición de Microsoft.EntityFrameworkCore.SqlServerAdd Microsoft.EntityFrameworkCore.SqlServer

  • En el menú Herramientas, seleccione Administrador de paquetes NuGet > Administrar paquetes NuGet para la solución.From the Tools menu, select NuGet Package Manager > Manage NuGet Packages for Solution.
  • Seleccione la pestaña Examinar y escriba Microsoft.EntityFrameworkCore.SqlServer en el cuadro de búsqueda.Select the Browse tab, and then enter Microsoft.EntityFrameworkCore.SqlServer in the search box.
  • Seleccione Microsoft.EntityFrameworkCore.SqlServer en el panel izquierdo.Select Microsoft.EntityFrameworkCore.SqlServer in the left pane.
  • Active la casilla Proyecto en el panel derecho y, después, seleccione Instalar.Select the Project check box in the right pane and then select Install.
  • Siga las instrucciones anteriores para agregar el paquete NuGet Microsoft.EntityFrameworkCore.InMemory.Use the preceding instructions to add the Microsoft.EntityFrameworkCore.InMemory NuGet package.

Administrador de paquetes de NuGet

Adición del contexto de la base de datos TodoContextAdd the TodoContext database context

  • Haga clic con el botón derecho en la carpeta Models y seleccione Agregar > Clase.Right-click the Models folder and select Add > Class. Asigne a la clase el nombre TodoContext y haga clic en Agregar.Name the class TodoContext and click Add.
  • Escriba el siguiente código:Enter the following code:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models
    {
        public class TodoContext : DbContext
        {
            public TodoContext(DbContextOptions<TodoContext> options)
                : base(options)
            {
            }
    
            public DbSet<TodoItem> TodoItems { get; set; }
        }
    }
    

Registro del contexto de base de datosRegister the database context

En ASP.NET Core, los servicios (como el contexto de la base de datos) deben registrarse con el contenedor de inserción de dependencias (DI).In ASP.NET Core, services such as the DB context must be registered with the dependency injection (DI) container. El contenedor proporciona el servicio a los controladores.The container provides the service to controllers.

Actualice Startup.cs con el siguiente código resaltado:Update Startup.cs with the following highlighted code:

// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TodoContext>(opt =>
               opt.UseInMemoryDatabase("TodoList"));
            services.AddControllers();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

El código anterior:The preceding code:

  • Elimina las declaraciones using no utilizadas.Removes unused using declarations.
  • Agrega el contexto de base de datos para el contenedor de DI.Adds the database context to the DI container.
  • Especifica que el contexto de base de datos usará una base de datos en memoria.Specifies that the database context will use an in-memory database.

Scaffolding de un controladorScaffold a controller

  • Haga clic con el botón derecho en la carpeta Controllers.Right-click the Controllers folder.

  • Seleccione Agregar > Nuevo elemento con scaffolding.Select Add > New Scaffolded Item.

  • Seleccione Controlador de API con acciones mediante Entity Framework y, después, seleccione Agregar.Select API Controller with actions, using Entity Framework, and then select Add.

  • En el cuadro de diálogo Add API Controller with actions, using Entity Framework (Agregar controlador de API con acciones mediante Entity Framework):In the Add API Controller with actions, using Entity Framework dialog:

    • Seleccione TodoItem (TodoApi.Models) en Clase de modelo.Select TodoItem (TodoApi.Models) in the Model class.
    • Seleccione TodoContext (TodoApi.Models) en Clase de contexto de datos.Select TodoContext (TodoApi.Models) in the Data context class.
    • Seleccione Agregar.Select Add.

El código generado:The generated code:

  • Marca la clase con el atributo [ApiController].Marks the class with the [ApiController] attribute. Este atributo indica que el controlador responde a las solicitudes de la API web.This attribute indicates that the controller responds to web API requests. Para información sobre comportamientos específicos que permite el atributo, consulte Creación de API web con ASP.NET Core.For information about specific behaviors that the attribute enables, see Creación de API web con ASP.NET Core.
  • Utiliza la inserción de dependencias para insertar el contexto de base de datos (TodoContext) en el controlador.Uses DI to inject the database context (TodoContext) into the controller. El contexto de base de datos se usa en cada uno de los métodos CRUD del controlador.The database context is used in each of the CRUD methods in the controller.

Examen del método create de PostTodoItemExamine the PostTodoItem create method

Reemplace la instrucción return en PostTodoItem para usar el operador nameof:Replace the return statement in the PostTodoItem to use the nameof operator:

// POST: api/TodoItems
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    //return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

El código anterior es un método HTTP POST, indicado por el atributo [HttpPost].The preceding code is an HTTP POST method, as indicated by the [HttpPost] attribute. El método obtiene el valor de tareas pendientes del cuerpo de la solicitud HTTP.The method gets the value of the to-do item from the body of the HTTP request.

El método CreatedAtAction realiza las acciones siguientes:The CreatedAtAction method:

  • Devuelve un código de estado HTTP 201 cuando se ha ejecutado correctamente.Returns an HTTP 201 status code if successful. HTTP 201 es la respuesta estándar para un método HTTP POST que crea un recurso en el servidor.HTTP 201 is the standard response for an HTTP POST method that creates a new resource on the server.
  • Agrega un encabezado Location a la respuesta.Adds a Location header to the response. El encabezado Location especifica el URI de la tarea pendiente recién creada.The Location header specifies the URI of the newly created to-do item. Para obtener más información, consulte 10.2.2 201 creado.For more information, see 10.2.2 201 Created.
  • Hace referencia a la acción GetTodoItem para crear el identificador URI del encabezado Location.References the GetTodoItem action to create the Location header's URI. La palabra clave nameof de C# se usa para evitar que se codifique de forma rígida el nombre de acción en la llamada a CreatedAtAction.The C# nameof keyword is used to avoid hard-coding the action name in the CreatedAtAction call.

Instalación de PostmanInstall Postman

En este tutorial se usa Postman para probar la API web.This tutorial uses Postman to test the web API.

  • Instale Postman.Install Postman
  • Inicie la aplicación web.Start the web app.
  • Inicie Postman.Start Postman.
  • Deshabilite Comprobación del certificado SSL.Disable SSL certificate verification
    • En Archivo > Configuración (pestaña General), deshabilite Comprobación del certificado SSL.From File > Settings (General tab), disable SSL certificate verification.

      Advertencia

      Vuelva a habilitar la comprobación del certificado SSL tras probar el controlador.Re-enable SSL certificate verification after testing the controller.

Prueba de PostTodoItem con PostmanTest PostTodoItem with Postman

  • Cree una nueva solicitud.Create a new request.

  • Establezca el método HTTP en POST.Set the HTTP method to POST.

  • Seleccione la pestaña Cuerpo.Select the Body tab.

  • Seleccione el botón de radio Raw (Sin formato).Select the raw radio button.

  • Establezca el tipo en JSON (application/json) .Set the type to JSON (application/json).

  • En el cuerpo de la solicitud, introduzca JSON para una tarea pendiente:In the request body enter JSON for a to-do item:

    {
      "name":"walk dog",
      "isComplete":true
    }
    
  • Seleccione Enviar.Select Send.

    Postman con solicitud de creación

Prueba del URI del encabezado de ubicaciónTest the location header URI

  • Seleccione la pestaña Encabezados en el panel Respuesta.Select the Headers tab in the Response pane.

  • Copie el valor de encabezado Ubicación:Copy the Location header value:

    Pestaña Encabezados de la consola de Postman

  • Establezca el método en GET.Set the method to GET.

  • Pegue el URI (por ejemplo, https://localhost:5001/api/TodoItems/1).Paste the URI (for example, https://localhost:5001/api/TodoItems/1).

  • Seleccione Enviar.Select Send.

Examen de los métodos GETExamine the GET methods

Estos métodos implementan dos puntos de conexión GET:These methods implement two GET endpoints:

  • GET /api/TodoItems
  • GET /api/TodoItems/{id}

Llame a los dos puntos de conexión desde un explorador o Postman para probar la aplicación.Test the app by calling the two endpoints from a browser or Postman. Por ejemplo:For example:

La llamada a GetTodoItems genera una respuesta similar a la siguiente:A response similar to the following is produced by the call to GetTodoItems:

[
  {
    "id": 1,
    "name": "Item1",
    "isComplete": false
  }
]

Prueba de Get con PostmanTest Get with Postman

  • Cree una nueva solicitud.Create a new request.
  • Establezca el método HTTP en GET.Set the HTTP method to GET.
  • Establezca la dirección URL de la solicitud en https://localhost:<port>/api/TodoItems.Set the request URL to https://localhost:<port>/api/TodoItems. Por ejemplo: https://localhost:5001/api/TodoItems.For example, https://localhost:5001/api/TodoItems.
  • Establezca Vista de dos paneles en Postman.Set Two pane view in Postman.
  • Seleccione Enviar.Select Send.

Esta aplicación utiliza una base de datos en memoria.This app uses an in-memory database. Si la aplicación se detiene y se inicia, la solicitud GET precedente no devolverá ningún dato.If the app is stopped and started, the preceding GET request will not return any data. Si no se devuelve ningún dato, publique los datos en la aplicación con POST.If no data is returned, POST data to the app.

Enrutamiento y rutas URLRouting and URL paths

El atributo [HttpGet] indica un método que responde a una solicitud HTTP GET.The [HttpGet] attribute denotes a method that responds to an HTTP GET request. La ruta de dirección URL para cada método se construye como sigue:The URL path for each method is constructed as follows:

  • Comience por la cadena de plantilla en el atributo Route del controlador:Start with the template string in the controller's Route attribute:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    {
        private readonly TodoContext _context;
    
        public TodoItemsController(TodoContext context)
        {
            _context = context;
        }
    
  • Reemplace [controller] por el nombre del controlador, que convencionalmente es el nombre de clase de controlador sin el sufijo "Controller".Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. En este ejemplo, el nombre de clase de controlador es TodoItemsController; por tanto, el nombre del controlador es "TodoItems".For this sample, the controller class name is TodoItemsController, so the controller name is "TodoItems". El enrutamiento en ASP.NET Core no distingue entre mayúsculas y minúsculas.ASP.NET Core routing is case insensitive.

  • Si el atributo [HttpGet] tiene una plantilla de ruta (por ejemplo, [HttpGet("products")]), anéxela a la ruta de acceso.If the [HttpGet] attribute has a route template (for example, [HttpGet("products")]), append that to the path. En este ejemplo no se usa una plantilla.This sample doesn't use a template. Para más información, vea Enrutamiento mediante atributos con atributos Http[Verb].For more information, see Attribute routing with Http[Verb] attributes.

En el siguiente método GetTodoItem, "{id}" es una variable de marcador de posición correspondiente al identificador único de la tarea pendiente.In the following GetTodoItem method, "{id}" is a placeholder variable for the unique identifier of the to-do item. Al invocar a GetTodoItem, el valor "{id}" de la URL se proporciona al método en su parámetro id.When GetTodoItem is invoked, the value of "{id}" in the URL is provided to the method in its id parameter.

// GET: api/TodoItems/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

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

    return todoItem;
}

Valores devueltosReturn values

El tipo de valor devuelto de los métodos GetTodoItems y GetTodoItem es ActionResult<T > type.The return type of the GetTodoItems and GetTodoItem methods is ActionResult<T> type. ASP.NET Core serializa automáticamente el objeto a JSON y escribe el JSON en el cuerpo del mensaje de respuesta.ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. El código de respuesta para este tipo de valor devuelto es el 200, suponiendo que no haya ninguna excepción no controlada.The response code for this return type is 200, assuming there are no unhandled exceptions. Las excepciones no controladas se convierten en errores 5xx.Unhandled exceptions are translated into 5xx errors.

Los tipos de valores devueltos ActionResult pueden representar una gama amplia de códigos de estado HTTP.ActionResult return types can represent a wide range of HTTP status codes. Por ejemplo, GetTodoItem puede devolver dos valores de estado diferentes:For example, GetTodoItem can return two different status values:

  • Si no hay ningún elemento que coincida con el identificador solicitado, el método devolverá un código de error 404 NotFound.If no item matches the requested ID, the method returns a 404 NotFound error code.
  • En caso contrario, el método devuelve 200 con un cuerpo de respuesta JSON.Otherwise, the method returns 200 with a JSON response body. Devolver item genera una respuesta HTTP 200.Returning item results in an HTTP 200 response.

Método PutTodoItemThe PutTodoItem method

Examine el método PutTodoItem:Examine the PutTodoItem method:

// PUT: api/TodoItems/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

PutTodoItem es similar a PostTodoItem, salvo por el hecho de que usa HTTP PUT.PutTodoItem is similar to PostTodoItem, except it uses HTTP PUT. La respuesta es 204 Sin contenido.The response is 204 (No Content). Según la especificación HTTP, una solicitud PUT requiere que el cliente envíe toda la entidad actualizada, no solo los cambios.According to the HTTP specification, a PUT request requires the client to send the entire updated entity, not just the changes. Para admitir actualizaciones parciales, use HTTP PATCH.To support partial updates, use HTTP PATCH.

Si recibe un error al llamar a PutTodoItem, llame a GET para asegurarse de que hay un elemento en la base de datos.If you get an error calling PutTodoItem, call GET to ensure there's an item in the database.

Prueba del método PutTodoItemTest the PutTodoItem method

En este ejemplo se usa una base de datos en memoria que se debe inicializar cada vez que se inicia la aplicación.This sample uses an in-memory database that must be initialized each time the app is started. Debe haber un elemento en la base de datos antes de que realice una llamada PUT.There must be an item in the database before you make a PUT call. Llame a GET para asegurarse de que hay un elemento en la base de datos antes de realizar una llamada PUT.Call GET to insure there's an item in the database before making a PUT call.

Actualice el elemento to-do que tiene el id. = 1 y establezca su nombre en "feed fish":Update the to-do item that has ID = 1 and set its name to "feed fish":

  {
    "ID":1,
    "name":"feed fish",
    "isComplete":true
  }

En la imagen siguiente, se muestra la actualización de Postman:The following image shows the Postman update:

Consola de Postman que muestra la respuesta 204 (Sin contenido)

Método DeleteTodoItemThe DeleteTodoItem method

Examine el método DeleteTodoItem:Examine the DeleteTodoItem method:

// DELETE: api/TodoItems/5
[HttpDelete("{id}")]
public async Task<ActionResult<TodoItem>> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return todoItem;
}

Prueba del método DeleteTodoItemTest the DeleteTodoItem method

Use Postman para eliminar una tarea pendiente:Use Postman to delete a to-do item:

  • Establezca el método en DELETE.Set the method to DELETE.
  • Establezca el URI del objeto que quiera eliminar (por ejemplo, https://localhost:5001/api/TodoItems/1).Set the URI of the object to delete (for example https://localhost:5001/api/TodoItems/1).
  • Seleccione Enviar.Select Send.

Llamar a la API web con JavaScriptCall the web API with JavaScript

Consulte Tutorial: Llamada a una API web de ASP.NET Core con JavaScript.See Tutorial: Call an ASP.NET Core web API with JavaScript.

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

  • Crear un proyecto de API web.Create a web API project.
  • Agregar una clase de modelo y un contexto de base de datos.Add a model class and a database context.
  • Agregar un controlador.Add a controller.
  • Agregar métodos CRUD.Add CRUD methods.
  • Configurar el enrutamiento y las rutas de dirección URL.Configure routing and URL paths.
  • Especificar los valores devueltos.Specify return values.
  • Llamar a la API web con Postman.Call the web API with Postman.
  • Llamar a la API web con JavaScript.Call the web API with JavaScript.

Al final, tendrá una API web que pueda administrar las tareas "pendientes" almacenadas en una base de datos relacional.At the end, you have a web API that can manage "to-do" items stored in a relational database.

Información generalOverview

En este tutorial se crea la siguiente API:This tutorial creates the following API:

APIAPI DescripciónDescription Cuerpo de la solicitudRequest body Cuerpo de la respuestaResponse body
GET /api/TodoItemsGET /api/TodoItems Obtener todas las tareas pendientesGet all to-do items NingunaNone Matriz de tareas pendientesArray of to-do items
GET /api/TodoItems/{id}GET /api/TodoItems/{id} Obtener un elemento por identificadorGet an item by ID NoneNone Tarea pendienteTo-do item
POST /api/TodoItemsPOST /api/TodoItems Incorporación de un nuevo elementoAdd a new item Tarea pendienteTo-do item Tarea pendienteTo-do item
PUT /api/TodoItems/{id}PUT /api/TodoItems/{id} Actualizar un elemento existente  Update an existing item   Tarea pendienteTo-do item NoneNone
DELETE /api/TodoItems/{id}    DELETE /api/TodoItems/{id}     Eliminar un elemento    Delete an item     NoneNone NoneNone

En el diagrama siguiente, se muestra el diseño de la aplicación.The following diagram shows the design of the app.

El cliente está representado por un cuadro a la izquierda.

Requisitos previosPrerequisites

Advertencia

Si usa Visual Studio 2017, consulte dotnet/sdk problema #3124 para información sobre las versiones del SDK de .NET Core que no funcionan con Visual Studio.If you use Visual Studio 2017, see dotnet/sdk issue #3124 for information about .NET Core SDK versions that don't work with Visual Studio.

Creación de un proyecto webCreate a web project

  • En el menú Archivo, seleccione Nuevo > Proyecto.From the File menu, select New > Project.
  • Seleccione la plantilla Aplicación web ASP.NET Core y haga clic en Siguiente.Select the ASP.NET Core Web Application template and click Next.
  • Asigne al proyecto el nombre TodoApi y haga clic en Crear.Name the project TodoApi and click Create.
  • En el cuadro de diálogo Crear una aplicación web ASP.NET Core, confirme que las opciones .NET Core y ASP.NET Core 2.2 estén seleccionadas.In the Create a new ASP.NET Core Web Application dialog, confirm that .NET Core and ASP.NET Core 2.2 are selected. Seleccione la plantilla API y haga clic en Crear.Select the API template and click Create. No seleccione Habilitar compatibilidad con Docker.Don't select Enable Docker Support.

Cuadro de diálogo de nuevo proyecto de VS

Prueba de la APITest the API

La plantilla del proyecto crea una API values.The project template creates a values API. Llame al método Get desde un explorador para probar la aplicación.Call the Get method from a browser to test the app.

Presione Ctrl+F5 para ejecutar la aplicación.Press Ctrl+F5 to run the app. Visual Studio inicia un explorador y navega hasta https://localhost:<port>/api/values, donde <port> es un número de puerto elegido aleatoriamente.Visual Studio launches a browser and navigates to https://localhost:<port>/api/values, where <port> is a randomly chosen port number.

Si aparece un cuadro de diálogo en que se le pregunta si debe confiar en el certificado de IIS Express, seleccione .If you get a dialog box that asks if you should trust the IIS Express certificate, select Yes. En el cuadro de diálogo Advertencia de seguridad que aparece a continuación, seleccione .In the Security Warning dialog that appears next, select Yes.

Se devuelve el siguiente JSON:The following JSON is returned:

["value1","value2"]

Incorporación de una clase de modeloAdd a model class

Un modelo es un conjunto de clases que representan los datos que la aplicación administra.A model is a set of classes that represent the data that the app manages. El modelo para esta aplicación es una clase TodoItem única.The model for this app is a single TodoItem class.

  • En el Explorador de soluciones, haga clic con el botón derecho en el proyecto.In Solution Explorer, right-click the project. Seleccione Agregar > Nueva carpeta.Select Add > New Folder. Asigne a la carpeta el nombre Models.Name the folder Models.

  • Haga clic con el botón derecho en la carpeta Models y seleccione Agregar > Clase.Right-click the Models folder and select Add > Class. Asigne a la clase el nombre TodoItem y seleccione Agregar.Name the class TodoItem and select Add.

  • Reemplace el código de plantilla por el código siguiente:Replace the template code with the following code:

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}

La propiedad Id funciona como clave única en una base de datos relacional.The Id property functions as the unique key in a relational database.

Las clases de modelo pueden ir en cualquier lugar del proyecto, pero convencionalmente e usa la carpeta Models.Model classes can go anywhere in the project, but the Models folder is used by convention.

Incorporación de un contexto de base de datosAdd a database context

El contexto de base de datos es la clase principal que coordina la funcionalidad de Entity Framework para un modelo de datos.The database context is the main class that coordinates Entity Framework functionality for a data model. Esta clase se crea derivándola de la clase Microsoft.EntityFrameworkCore.DbContext.This class is created by deriving from the Microsoft.EntityFrameworkCore.DbContext class.

  • Haga clic con el botón derecho en la carpeta Models y seleccione Agregar > Clase.Right-click the Models folder and select Add > Class. Asigne a la clase el nombre TodoContext y haga clic en Agregar.Name the class TodoContext and click Add.
  • Reemplace el código de plantilla por el código siguiente:Replace the template code with the following code:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models
    {
        public class TodoContext : DbContext
        {
            public TodoContext(DbContextOptions<TodoContext> options)
                : base(options)
            {
            }
    
            public DbSet<TodoItem> TodoItems { get; set; }
        }
    }
    

Registro del contexto de base de datosRegister the database context

En ASP.NET Core, los servicios (como el contexto de la base de datos) deben registrarse con el contenedor de inserción de dependencias (DI).In ASP.NET Core, services such as the DB context must be registered with the dependency injection (DI) container. El contenedor proporciona el servicio a los controladores.The container provides the service to controllers.

Actualice Startup.cs con el siguiente código resaltado:Update Startup.cs with the following highlighted code:

// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the 
        //container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TodoContext>(opt =>
                opt.UseInMemoryDatabase("TodoList"));
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP 
        //request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for 
                // production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseMvc();
        }
    }
}

El código anterior:The preceding code:

  • Elimina las declaraciones using no utilizadas.Removes unused using declarations.
  • Agrega el contexto de base de datos para el contenedor de DI.Adds the database context to the DI container.
  • Especifica que el contexto de base de datos usará una base de datos en memoria.Specifies that the database context will use an in-memory database.

Incorporación de un controladorAdd a controller

  • Haga clic con el botón derecho en la carpeta Controllers.Right-click the Controllers folder.

  • Seleccione Agregar > Nuevo elemento.Select Add > New Item.

  • En el cuadro de diálogo Agregar nuevo elemento, seleccione la plantilla Clase de controlador de API.In the Add New Item dialog, select the API Controller Class template.

  • Asigne a la clase el nombre TodoController y seleccione Agregar.Name the class TodoController, and select Add.

    Cuadro de diálogo Agregar nuevo elemento con la palabra "controller" en el cuadro de búsqueda y la opción Clase de controlador de API web seleccionada

  • Reemplace el código de plantilla por el código siguiente:Replace the template code with the following code:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using TodoApi.Models;
    
    namespace TodoApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class TodoController : ControllerBase
        {
            private readonly TodoContext _context;
    
            public TodoController(TodoContext context)
            {
                _context = context;
    
                if (_context.TodoItems.Count() == 0)
                {
                    // Create a new TodoItem if collection is empty,
                    // which means you can't delete all TodoItems.
                    _context.TodoItems.Add(new TodoItem { Name = "Item1" });
                    _context.SaveChanges();
                }
            }
        }
    }
    

El código anterior:The preceding code:

  • Define una clase de controlador de API sin métodos.Defines an API controller class without methods.
  • Marca la clase con el atributo [ApiController].Marks the class with the [ApiController] attribute. Este atributo indica que el controlador responde a las solicitudes de la API web.This attribute indicates that the controller responds to web API requests. Para información sobre comportamientos específicos que permite el atributo, consulte Creación de API web con ASP.NET Core.For information about specific behaviors that the attribute enables, see Creación de API web con ASP.NET Core.
  • Utiliza la inserción de dependencias para insertar el contexto de base de datos (TodoContext) en el controlador.Uses DI to inject the database context (TodoContext) into the controller. El contexto de base de datos se usa en cada uno de los métodos CRUD del controlador.The database context is used in each of the CRUD methods in the controller.
  • Si la base de datos está vacía, le agrega un elemento denominado Item1.Adds an item named Item1 to the database if the database is empty. Este código está en el constructor, de manera que se ejecuta cada vez que hay una nueva solicitud HTTP.This code is in the constructor, so it runs every time there's a new HTTP request. Si elimina todos los elementos, el constructor volverá a crear Item1 la próxima vez que se llame a un método de API.If you delete all items, the constructor creates Item1 again the next time an API method is called. De este modo, es posible que parezca que la eliminación no ha funcionado, cuando en realidad sí lo ha hecho.So it may look like the deletion didn't work when it actually did work.

Incorporación de métodos GetAdd Get methods

Para proporcionar una API que recupere tareas pendientes, agregue estos métodos a la clase TodoController:To provide an API that retrieves to-do items, add the following methods to the TodoController class:

// GET: api/Todo
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
{
    return await _context.TodoItems.ToListAsync();
}

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

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

    return todoItem;
}

Estos métodos implementan dos puntos de conexión GET:These methods implement two GET endpoints:

  • GET /api/todo
  • GET /api/todo/{id}

Detenga la aplicación si todavía está en ejecución.Stop the app if it's still running. Luego, ejecútela de nuevo para incluir los últimos cambios.Then run it again to include the latest changes.

Llame a los dos puntos de conexión desde un explorador para probar la aplicación.Test the app by calling the two endpoints from a browser. Por ejemplo:For example:

  • https://localhost:<port>/api/todo
  • https://localhost:<port>/api/todo/1

La llamada a GetTodoItems genera la siguiente respuesta HTTP:The following HTTP response is produced by the call to GetTodoItems:

[
  {
    "id": 1,
    "name": "Item1",
    "isComplete": false
  }
]

Enrutamiento y rutas URLRouting and URL paths

El atributo [HttpGet] indica un método que responde a una solicitud HTTP GET.The [HttpGet] attribute denotes a method that responds to an HTTP GET request. La ruta de dirección URL para cada método se construye como sigue:The URL path for each method is constructed as follows:

  • Comience por la cadena de plantilla en el atributo Route del controlador:Start with the template string in the controller's Route attribute:

    namespace TodoApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class TodoController : ControllerBase
        {
            private readonly TodoContext _context;
    
  • Reemplace [controller] por el nombre del controlador, que convencionalmente es el nombre de clase de controlador sin el sufijo "Controller".Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. En este ejemplo, el nombre de clase de controlador es TodoController; por tanto, el nombre del controlador es "todo".For this sample, the controller class name is TodoController, so the controller name is "todo". El enrutamiento en ASP.NET Core no distingue entre mayúsculas y minúsculas.ASP.NET Core routing is case insensitive.

  • Si el atributo [HttpGet] tiene una plantilla de ruta (por ejemplo, [HttpGet("products")]), anéxela a la ruta de acceso.If the [HttpGet] attribute has a route template (for example, [HttpGet("products")]), append that to the path. En este ejemplo no se usa una plantilla.This sample doesn't use a template. Para más información, vea Enrutamiento mediante atributos con atributos Http[Verb].For more information, see Attribute routing with Http[Verb] attributes.

En el siguiente método GetTodoItem, "{id}" es una variable de marcador de posición correspondiente al identificador único de la tarea pendiente.In the following GetTodoItem method, "{id}" is a placeholder variable for the unique identifier of the to-do item. Al invocar a GetTodoItem, el valor "{id}" de la dirección URL se proporciona al método en su parámetro id.When GetTodoItem is invoked, the value of "{id}" in the URL is provided to the method in itsid parameter.

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

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

    return todoItem;
}

Valores devueltosReturn values

El tipo de valor devuelto de los métodos GetTodoItems y GetTodoItem es ActionResult<T > type.The return type of the GetTodoItems and GetTodoItem methods is ActionResult<T> type. ASP.NET Core serializa automáticamente el objeto a JSON y escribe el JSON en el cuerpo del mensaje de respuesta.ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. El código de respuesta para este tipo de valor devuelto es el 200, suponiendo que no haya ninguna excepción no controlada.The response code for this return type is 200, assuming there are no unhandled exceptions. Las excepciones no controladas se convierten en errores 5xx.Unhandled exceptions are translated into 5xx errors.

Los tipos de valores devueltos ActionResult pueden representar una gama amplia de códigos de estado HTTP.ActionResult return types can represent a wide range of HTTP status codes. Por ejemplo, GetTodoItem puede devolver dos valores de estado diferentes:For example, GetTodoItem can return two different status values:

  • Si no hay ningún elemento que coincida con el identificador solicitado, el método devolverá un código de error 404 NotFound.If no item matches the requested ID, the method returns a 404 NotFound error code.
  • En caso contrario, el método devuelve 200 con un cuerpo de respuesta JSON.Otherwise, the method returns 200 with a JSON response body. Devolver item genera una respuesta HTTP 200.Returning item results in an HTTP 200 response.

Prueba del método GetTodoItemsTest the GetTodoItems method

En este tutorial se usa Postman para probar la API web.This tutorial uses Postman to test the web API.

  • Instale Postman.Install Postman.
  • Inicie la aplicación web.Start the web app.
  • Inicie Postman.Start Postman.
  • Deshabilite Comprobación del certificado SSL.Disable SSL certificate verification.
  • En Archivo > Configuración (pestaña General), deshabilite Comprobación del certificado SSL.From File > Settings (General tab), disable SSL certificate verification.

Advertencia

Vuelva a habilitar la comprobación del certificado SSL tras probar el controlador.Re-enable SSL certificate verification after testing the controller.

  • Cree una nueva solicitud.Create a new request.
    • Establezca el método HTTP en GET.Set the HTTP method to GET.
    • Establezca la dirección URL de la solicitud en https://localhost:<port>/api/todo.Set the request URL to https://localhost:<port>/api/todo. Por ejemplo: https://localhost:5001/api/todo.For example, https://localhost:5001/api/todo.
  • Establezca Vista de dos paneles en Postman.Set Two pane view in Postman.
  • Seleccione Enviar.Select Send.

Postman con solicitud Get

Incorporación de un método CreateAdd a Create method

Agregue el siguiente método PostTodoItem en Controllers/TodoController.cs:Add the following PostTodoItem method inside of Controllers/TodoController.cs:

// POST: api/Todo
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem item)
{
    _context.TodoItems.Add(item);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item);
}

El código anterior es un método HTTP POST, indicado por el atributo [HttpPost].The preceding code is an HTTP POST method, as indicated by the [HttpPost] attribute. El método obtiene el valor de tareas pendientes del cuerpo de la solicitud HTTP.The method gets the value of the to-do item from the body of the HTTP request.

El método CreatedAtAction realiza las acciones siguientes:The CreatedAtAction method:

  • Devuelve un código de estado HTTP 201 cuando se ha ejecutado correctamente.Returns an HTTP 201 status code, if successful. HTTP 201 es la respuesta estándar para un método HTTP POST que crea un recurso en el servidor.HTTP 201 is the standard response for an HTTP POST method that creates a new resource on the server.

  • Agrega un encabezado Location a la respuesta.Adds a Location header to the response. El encabezado Location especifica el identificador URI de la tarea pendiente recién creada.The Location header specifies the URI of the newly created to-do item. Para obtener más información, consulte 10.2.2 201 creado.For more information, see 10.2.2 201 Created.

  • Hace referencia a la acción GetTodoItem para crear el identificador URI del encabezado Location.References the GetTodoItem action to create the Location header's URI. La palabra clave nameof de C# se usa para evitar que se codifique de forma rígida el nombre de acción en la llamada a CreatedAtAction.The C# nameof keyword is used to avoid hard-coding the action name in the CreatedAtAction call.

    // GET: api/Todo/5
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);
    
        if (todoItem == null)
        {
            return NotFound();
        }
    
        return todoItem;
    }
    

Prueba del método PostTodoItemTest the PostTodoItem method

  • Compile el proyecto.Build the project.

  • En Postman, establezca el método HTTP en POST.In Postman, set the HTTP method to POST.

  • Seleccione la pestaña Cuerpo.Select the Body tab.

  • Seleccione el botón de radio Raw (Sin formato).Select the raw radio button.

  • Establezca el tipo en JSON (application/json) .Set the type to JSON (application/json).

  • En el cuerpo de la solicitud, introduzca JSON para una tarea pendiente:In the request body enter JSON for a to-do item:

    {
      "name":"walk dog",
      "isComplete":true
    }
    
  • Seleccione Enviar.Select Send.

    Postman con solicitud de creación

    Si recibe un error 405 (Método no permitido), probablemente sea el resultado de no haber compilado el proyecto después de agregar el método PostTodoItem.If you get a 405 Method Not Allowed error, it's probably the result of not compiling the project after adding the PostTodoItem method.

Prueba del URI del encabezado de ubicaciónTest the location header URI

  • Seleccione la pestaña Encabezados en el panel Respuesta.Select the Headers tab in the Response pane.

  • Copie el valor de encabezado Ubicación:Copy the Location header value:

    Pestaña Encabezados de la consola de Postman

  • Establezca el método en GET.Set the method to GET.

  • Pegue el URI (por ejemplo, https://localhost:5001/api/Todo/2).Paste the URI (for example, https://localhost:5001/api/Todo/2).

  • Seleccione Enviar.Select Send.

Incorporación de un método PutTodoItemAdd a PutTodoItem method

Agregue el siguiente método PutTodoItem:Add the following PutTodoItem method:

// PUT: api/Todo/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem item)
{
    if (id != item.Id)
    {
        return BadRequest();
    }

    _context.Entry(item).State = EntityState.Modified;
    await _context.SaveChangesAsync();

    return NoContent();
}

PutTodoItem es similar a PostTodoItem, salvo por el hecho de que usa HTTP PUT.PutTodoItem is similar to PostTodoItem, except it uses HTTP PUT. La respuesta es 204 Sin contenido.The response is 204 (No Content). Según la especificación HTTP, una solicitud PUT requiere que el cliente envíe toda la entidad actualizada, no solo los cambios.According to the HTTP specification, a PUT request requires the client to send the entire updated entity, not just the changes. Para admitir actualizaciones parciales, use HTTP PATCH.To support partial updates, use HTTP PATCH.

Si recibe un error al llamar a PutTodoItem, llame a GET para asegurarse de que hay un elemento en la base de datos.If you get an error calling PutTodoItem, call GET to ensure there's an item in the database.

Prueba del método PutTodoItemTest the PutTodoItem method

En este ejemplo se usa una base de datos en memoria que se debe inicializar cada vez que se inicia la aplicación.This sample uses an in-memory database that must be initialized each time the app is started. Debe haber un elemento en la base de datos antes de que realice una llamada PUT.There must be an item in the database before you make a PUT call. Llame a GET para asegurarse de que hay un elemento en la base de datos antes de realizar una llamada PUT.Call GET to insure there's an item in the database before making a PUT call.

Actualice la tarea pendiente que tiene el id. = 1 y establezca su nombre en "feed fish":Update the to-do item that has id = 1 and set its name to "feed fish":

  {
    "ID":1,
    "name":"feed fish",
    "isComplete":true
  }

En la imagen siguiente, se muestra la actualización de Postman:The following image shows the Postman update:

Consola de Postman que muestra la respuesta 204 (Sin contenido)

Incorporación de un método DeleteTodoItemAdd a DeleteTodoItem method

Agregue el siguiente método DeleteTodoItem:Add the following DeleteTodoItem method:

// DELETE: api/Todo/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

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

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

La respuesta de DeleteTodoItem es 204 (Sin contenido).The DeleteTodoItem response is 204 (No Content).

Prueba del método DeleteTodoItemTest the DeleteTodoItem method

Use Postman para eliminar una tarea pendiente:Use Postman to delete a to-do item:

  • Establezca el método en DELETE.Set the method to DELETE.
  • Establezca el URI del objeto que quiera eliminar (por ejemplo, https://localhost:5001/api/todo/1).Set the URI of the object to delete (for example https://localhost:5001/api/todo/1).
  • Seleccione Enviar.Select Send.

La aplicación de ejemplo permite eliminar todos los elementos.The sample app allows you to delete all the items. Sin embargo, al eliminar el último elemento, se creará uno nuevo en el constructor de clase de modelo la próxima vez que se llame a la API.However, when the last item is deleted, a new one is created by the model class constructor the next time the API is called.

Llamar a la API web con JavaScriptCall the web API with JavaScript

En esta sección, se agrega una página HTML que usa JavaScript para llamar a la API web.In this section, an HTML page is added that uses JavaScript to call the web API. JQuery inicia la solicitud.jQuery initiates the request. JavaScript actualiza la página con los detalles de la respuesta de la API web.JavaScript updates the page with the details from the web API's response.

Configure la aplicación para atender archivos estáticos y habilitar la asignación de archivos predeterminada mediante la actualización de Startup.cs con el siguiente código resaltado:Configure the app to serve static files and enable default file mapping by updating Startup.cs with the following highlighted code:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        // The default HSTS value is 30 days. You may want to change this for 
        // production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseDefaultFiles();
    app.UseStaticFiles();
    app.UseHttpsRedirection();
    app.UseMvc();
}

Cree una carpeta wwwroot en el directorio del proyecto.Create a wwwroot folder in the project directory.

Agregue un archivo HTML denominado index.html al directorio wwwroot.Add an HTML file named index.html to the wwwroot directory. Reemplace el contenido por el siguiente marcado:Replace its contents with the following markup:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>To-do CRUD</title>
    <style>
        input[type='submit'], button, [aria-label] {
            cursor: pointer;
        }

        #spoiler {
            display: none;
        }

        table {
            font-family: Arial, sans-serif;
            border: 1px solid;
            border-collapse: collapse;
        }

        th {
            background-color: #0066CC;
            color: white;
        }

        td {
            border: 1px solid;
            padding: 5px;
        }
    </style>
</head>
<body>
    <h1>To-do CRUD</h1>
    <h3>Add</h3>
    <form action="javascript:void(0);" method="POST" onsubmit="addItem()">
        <input type="text" id="add-name" placeholder="New to-do">
        <input type="submit" value="Add">
    </form>

    <div id="spoiler">
        <h3>Edit</h3>
        <form class="my-form">
            <input type="hidden" id="edit-id">
            <input type="checkbox" id="edit-isComplete">
            <input type="text" id="edit-name">
            <input type="submit" value="Save">
            <a onclick="closeInput()" aria-label="Close">&#10006;</a>
        </form>
    </div>

    <p id="counter"></p>

    <table>
        <tr>
            <th>Is Complete</th>
            <th>Name</th>
            <th></th>
            <th></th>
        </tr>
        <tbody id="todos"></tbody>
    </table>

    <script src="https://code.jquery.com/jquery-3.3.1.min.js"
            integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
            crossorigin="anonymous"></script>
    <script src="site.js"></script>
</body>
</html>

Agregue un archivo JavaScript denominado site.js al directorio wwwroot.Add a JavaScript file named site.js to the wwwroot directory. Reemplace el contenido por el siguiente código:Replace its contents with the following code:

const uri = "api/todo";
let todos = null;
function getCount(data) {
  const el = $("#counter");
  let name = "to-do";
  if (data) {
    if (data > 1) {
      name = "to-dos";
    }
    el.text(data + " " + name);
  } else {
    el.text("No " + name);
  }
}

$(document).ready(function() {
  getData();
});

function getData() {
  $.ajax({
    type: "GET",
    url: uri,
    cache: false,
    success: function(data) {
      const tBody = $("#todos");

      $(tBody).empty();

      getCount(data.length);

      $.each(data, function(key, item) {
        const tr = $("<tr></tr>")
          .append(
            $("<td></td>").append(
              $("<input/>", {
                type: "checkbox",
                disabled: true,
                checked: item.isComplete
              })
            )
          )
          .append($("<td></td>").text(item.name))
          .append(
            $("<td></td>").append(
              $("<button>Edit</button>").on("click", function() {
                editItem(item.id);
              })
            )
          )
          .append(
            $("<td></td>").append(
              $("<button>Delete</button>").on("click", function() {
                deleteItem(item.id);
              })
            )
          );

        tr.appendTo(tBody);
      });

      todos = data;
    }
  });
}

function addItem() {
  const item = {
    name: $("#add-name").val(),
    isComplete: false
  };

  $.ajax({
    type: "POST",
    accepts: "application/json",
    url: uri,
    contentType: "application/json",
    data: JSON.stringify(item),
    error: function(jqXHR, textStatus, errorThrown) {
      alert("Something went wrong!");
    },
    success: function(result) {
      getData();
      $("#add-name").val("");
    }
  });
}

function deleteItem(id) {
  $.ajax({
    url: uri + "/" + id,
    type: "DELETE",
    success: function(result) {
      getData();
    }
  });
}

function editItem(id) {
  $.each(todos, function(key, item) {
    if (item.id === id) {
      $("#edit-name").val(item.name);
      $("#edit-id").val(item.id);
      $("#edit-isComplete")[0].checked = item.isComplete;
    }
  });
  $("#spoiler").css({ display: "block" });
}

$(".my-form").on("submit", function() {
  const item = {
    name: $("#edit-name").val(),
    isComplete: $("#edit-isComplete").is(":checked"),
    id: $("#edit-id").val()
  };

  $.ajax({
    url: uri + "/" + $("#edit-id").val(),
    type: "PUT",
    accepts: "application/json",
    contentType: "application/json",
    data: JSON.stringify(item),
    success: function(result) {
      getData();
    }
  });

  closeInput();
  return false;
});

function closeInput() {
  $("#spoiler").css({ display: "none" });
}

Puede que sea necesario realizar un cambio en la configuración de inicio del proyecto de ASP.NET Core para probar la página HTML localmente:A change to the ASP.NET Core project's launch settings may be required to test the HTML page locally:

  • Abra Properties\launchSettings.json.Open Properties\launchSettings.json.
  • Quite la propiedad launchUrl para forzar a la aplicación a abrirse en index.html, esto es, el archivo predeterminado del proyecto.Remove the launchUrl property to force the app to open at index.html—the project's default file.

En este ejemplo se llama a todos los métodos CRUD de la API web.This sample calls all of the CRUD methods of the web API. A continuación, encontrará algunas explicaciones de las llamadas a la API.Following are explanations of the calls to the API.

Obtención de una lista de tareas pendientesGet a list of to-do items

jQuery envía una solicitud HTTP GET a la API web, que devuelve código JSON que representa una matriz de tareas pendientes.jQuery sends an HTTP GET request to the web API, which returns JSON representing an array of to-do items. La función de devolución de llamada success se invoca si la solicitud se realiza correctamente.The success callback function is invoked if the request succeeds. En la devolución de llamada, el DOM se actualiza con la información de la tarea pendiente.In the callback, the DOM is updated with the to-do information.

$(document).ready(function() {
  getData();
});

function getData() {
  $.ajax({
    type: "GET",
    url: uri,
    cache: false,
    success: function(data) {
      const tBody = $("#todos");

      $(tBody).empty();

      getCount(data.length);

      $.each(data, function(key, item) {
        const tr = $("<tr></tr>")
          .append(
            $("<td></td>").append(
              $("<input/>", {
                type: "checkbox",
                disabled: true,
                checked: item.isComplete
              })
            )
          )
          .append($("<td></td>").text(item.name))
          .append(
            $("<td></td>").append(
              $("<button>Edit</button>").on("click", function() {
                editItem(item.id);
              })
            )
          )
          .append(
            $("<td></td>").append(
              $("<button>Delete</button>").on("click", function() {
                deleteItem(item.id);
              })
            )
          );

        tr.appendTo(tBody);
      });

      todos = data;
    }
  });
}

Incorporación de una tarea pendienteAdd a to-do item

jQuery envía una solicitud HTTP POST con la tarea pendiente en el cuerpo de dicha solicitud.jQuery sends an HTTP POST request with the to-do item in the request body. Las opciones accepts y contentType se establecen en application/json para especificar el tipo de medio que se va a recibir y a enviar.The accepts and contentType options are set to application/json to specify the media type being received and sent. La tarea pendiente se convierte en JSON mediante JSON.stringify.The to-do item is converted to JSON by using JSON.stringify. Cuando la API devuelve un código de estado correcto, se invoca la función getData para actualizar la tabla HTML.When the API returns a successful status code, the getData function is invoked to update the HTML table.

function addItem() {
  const item = {
    name: $("#add-name").val(),
    isComplete: false
  };

  $.ajax({
    type: "POST",
    accepts: "application/json",
    url: uri,
    contentType: "application/json",
    data: JSON.stringify(item),
    error: function(jqXHR, textStatus, errorThrown) {
      alert("Something went wrong!");
    },
    success: function(result) {
      getData();
      $("#add-name").val("");
    }
  });
}

Actualizar una tarea pendienteUpdate a to-do item

El hecho de actualizar una tarea pendiente es similar al de agregar una.Updating a to-do item is similar to adding one. El valor url cambia para agregar el identificador único del elemento, y type es PUT.The url changes to add the unique identifier of the item, and the type is PUT.

$.ajax({
  url: uri + "/" + $("#edit-id").val(),
  type: "PUT",
  accepts: "application/json",
  contentType: "application/json",
  data: JSON.stringify(item),
  success: function(result) {
    getData();
  }
});

Eliminar una tarea pendienteDelete a to-do item

Para eliminar una tarea pendiente, hay que establecer el valor type de la llamada de AJAX en DELETE y especificar el identificador único de la tarea en la dirección URL.Deleting a to-do item is accomplished by setting the type on the AJAX call to DELETE and specifying the item's unique identifier in the URL.

$.ajax({
  url: uri + "/" + id,
  type: "DELETE",
  success: function(result) {
    getData();
  }
});

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 3.0.IdentityServer4 is an OpenID Connect and OAuth 2.0 framework for ASP.NET Core 3.0. 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.

Recursos adicionalesAdditional resources

Vea o descargue el código de ejemplo para este tutorial.View or download sample code for this tutorial. Vea cómo descargarlo.See how to download.

Para obtener más información, vea los siguientes recursos:For more information, see the following resources: