Habilitando el CORS en ASP.NET Core 2.1 | by Adonis Mendoza | Medium

¿Te gustaría aprender ASP.NET Core Empresarial?
Tenemos lo que necesitas .¡Haz clic aquí!

Este tutorial enseña los conceptos básicos de la creación de una API web con ASP.NET Core. En este tutorial, aprenderás a:

– Crear un proyecto de API web.

– Agregar una clase de modelo y un contexto de base de datos.

– Andamia un controlador con métodos CRUD.

– Configurar el enrutamiento, las rutas de URL y los valores de retorno.

– Llamar a la API web con Postman.

Al final, tiene una API web que puede administrar elementos “pendientes” almacenados en una base de datos.

Descripción general

Este tutorial crea la siguiente API:

APIDescripciónCuerpo de la solicitudCuerpo de respuesta
GET /api/TodoItemsObtener todos los elementos pendientesNingunoMatriz de tareas pendientes
GET /api/TodoItems/{id}Obtener un artículo por IDNingunoElemento de tarea
POST /api/TodoItemsAgregar un artículo nuevoElemento de tareaElemento de tarea
PUT /api/TodoItems/{id}Actualizar un artículo existente  Elemento de tareaNinguno
DELETE /api/TodoItems/{id}    Eliminar un elemento    NingunoNinguno

El siguiente diagrama muestra el diseño de la aplicación.

El cliente está representado por un cuadro a la izquierda.  Envía una solicitud y recibe una respuesta de la aplicación, un cuadro dibujado a la derecha.  Dentro del cuadro de la aplicación, tres cuadros representan el controlador, el modelo y la capa de acceso a los datos.  La solicitud entra en el controlador de la aplicación y se producen operaciones de lectura / escritura entre el controlador y la capa de acceso a datos.  El modelo se serializa y se devuelve al cliente en la respuesta.

Prerrequisitos

Crea un proyecto web

  • En el menú Archivo , seleccione Nuevo > Proyecto .
  • Seleccione la plantilla de API web ASP.NET Core y haga clic en Siguiente .
  • Nombra el proyecto TodoApi y haz clic en Crear .
  • En el cuadro de diálogo Crear una nueva aplicación web ASP.NET Core , confirme que .NET Core y ASP.NET Core 5.0 están seleccionados. Seleccione la plantilla de API y haga clic en Crear .
VS diálogo de nuevo proyecto

Prueba el proyecto

La plantilla del proyecto crea una WeatherForecastAPI compatible con Swagger .

Presione Ctrl + F5 para ejecutar sin el depurador.

Visual Studio muestra el siguiente cuadro de diálogo:

Este proyecto está configurado para utilizar SSL.  Para evitar las advertencias de SSL en el navegador, puede optar por confiar en el certificado autofirmado que IIS Express ha generado.  ¿Le gustaría confiar en el certificado SSL de IIS Express?

Seleccione  si confía en el certificado SSL de IIS Express.

Aparece el siguiente cuadro de diálogo:

Diálogo de advertencia de seguridad

Seleccione  si acepta confiar en el certificado de desarrollo.

Para obtener información sobre cómo confiar en el navegador Firefox, consulte Error de certificado SEC_ERROR_INADEQUATE_KEY_USAGE de Firefox .

Lanzamiento de Visual Studio:

  • El servidor web IIS Express.
  • El navegador predeterminado y navega hacia https://localhost:<port>/swagger/index.html, donde <port>es un número de puerto elegido al azar.

Se /swagger/index.htmlmuestra la página Swagger . Seleccione OBTENER > Pruébelo > Ejecutar . La página muestra:

  • El comando Curl para probar la API WeatherForecast.
  • La URL para probar la API WeatherForecast.
  • El código de respuesta, el cuerpo y los encabezados.
  • Un cuadro de lista desplegable con tipos de medios y el valor y el esquema de ejemplo.

Si la página Swagger no aparece, vea este problema de GitHub .

Swagger se utiliza para generar documentación útil y páginas de ayuda para API web. Este tutorial se centra en la creación de una API web. Para obtener más información sobre Swagger, consulte la documentación de la API web de ASP.NET Core con Swagger / OpenAPI .

Copie y pegue la URL de solicitud en el navegador: https://localhost:<port>/WeatherForecast

Se devuelve JSON similar al siguiente:JSONDupdo

[
    {
        "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"
    }
]

Actualiza launchUrl

En Propiedades \ launchSettings.json , actualice launchUrlde "swagger""api/TodoItems":JSONDupdo

"launchUrl": "api/TodoItems",

Debido a que Swagger se ha eliminado, el marcado anterior cambia la URL que se inicia al método GET del controlador agregado en las siguientes secciones.

Agregar una clase de modelo

Un modelo es un conjunto de clases que representan los datos que administra la aplicación. El modelo de esta aplicación es de una sola TodoItemclase.

  • En el Explorador de soluciones , haga clic con el botón derecho en el proyecto. Seleccione Agregar > Nueva carpeta . Nombra la carpeta Modelos .
  • Haga clic con el botón derecho en la carpeta Modelos y seleccione Agregar > Clase . Nombre la clase TodoItem y seleccione Agregar .
  • Reemplace el código de la plantilla con lo siguiente:

C#Dupdo

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

La Idpropiedad funciona como clave única en una base de datos relacional.

Las clases de modelo pueden ir a cualquier parte del proyecto, pero la carpeta Modelos se usa por convención.

Agregar un contexto de base de datos

El contexto de la base de datos es la clase principal que coordina la funcionalidad de Entity Framework para un modelo de datos. Esta clase se crea derivando de la clase Microsoft.EntityFrameworkCore.DbContext .

Agregar paquetes NuGet

  • En el menú Herramientas , seleccione Administrador de paquetes NuGet> Administrar paquetes NuGet para la solución .
  • Seleccione la pestaña Examinar y luego ingrese Microsoft.EntityFrameworkCore.InMemoryen el cuadro de búsqueda.
  • Seleccione Microsoft.EntityFrameworkCore.InMemoryen el panel izquierdo.
  • Seleccione la casilla de verificación Proyecto en el panel derecho y luego seleccione Instalar .
Administrador de paquetes NuGet

Agregar el contexto de la base de datos de TodoContext

  • Haga clic con el botón derecho en la carpeta Modelos y seleccione Agregar > Clase . Nombra la clase TodoContext y haz clic en Agregar .
  • Ingrese el siguiente código:C#Dupdousing Microsoft.EntityFrameworkCore; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } } }

Registrar el contexto de la base de datos

En ASP.NET Core, los servicios como el contexto de base de datos deben registrarse con el contenedor de inyección de dependencia (DI) . El contenedor proporciona el servicio a los controladores.

Actualice Startup.cs con el siguiente código:C#Dupdo

// 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:

  • Elimina las llamadas Swagger.
  • Elimina las usingdeclaraciones no utilizadas .
  • Agrega el contexto de la base de datos al contenedor DI.
  • Especifica que el contexto de la base de datos utilizará una base de datos en memoria.

Andamio de un controlador

  • Haga clic con el botón derecho en la carpeta Controladores .
  • Seleccione Agregar > Nuevo elemento con andamio .
  • Seleccione API Controller con acciones, usando Entity Framework , y luego seleccione Agregar .
  • En el Agregar controlador de API con acciones, usando el cuadro de diálogo Entity Framework :
    • Seleccione TodoItem (TodoApi.Models) en la clase Model .
    • Seleccione TodoContext (TodoApi.Models) en la clase de contexto de datos .
    • Seleccione Agregar .

El código generado:

  • Marca la clase con el [ApiController]atributo. Este atributo indica que el controlador responde a las solicitudes de la API web. Para obtener información sobre los comportamientos específicos que habilita el atributo, consulte Crear API web con ASP.NET Core .
  • Utiliza DI para inyectar el contexto de la base de datos ( TodoContext) en el controlador. El contexto de la base de datos se utiliza en cada uno de los métodos CRUD en el controlador.

Las plantillas ASP.NET Core para:

  • Los controladores con vistas se incluyen [action]en la plantilla de ruta.
  • Los controladores de API no se incluyen [action]en la plantilla de ruta.

Cuando el [action]token no está en la plantilla de ruta, el nombre de la acción se excluye de la ruta. Es decir, el nombre del método asociado a la acción no se usa en la ruta coincidente.

Actualizar el método de creación de PostTodoItem

Actualice la declaración de retorno en el PostTodoItempara usar el operador nameof :C#Dupdo

// 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, como lo indica el [HttpPost]atributo. El método obtiene el valor de la tarea pendiente del cuerpo de la solicitud HTTP.

Para obtener más información, consulte Enrutamiento de atributos con atributos Http [Verb] .

El método CreatedAtAction :

  • Devuelve un código de estado HTTP 201 si tiene éxito. HTTP 201 es la respuesta estándar para un método HTTP POST que crea un nuevo recurso en el servidor.
  • Agrega un encabezado de ubicación a la respuesta. El Locationencabezado especifica el URI de la tarea pendiente recién creada. Para obtener más información, consulte 10.2.2 201 Creado .
  • Hace referencia a la GetTodoItemacción para crear el LocationURI del encabezado. La nameofpalabra clave C # se usa para evitar codificar el nombre de la acción en la CreatedAtActionllamada.

Instalar cartero

Este tutorial utiliza Postman para probar la API web.

  • Instalar cartero
  • Inicie la aplicación web.
  • Inicie Postman.
  • Desactivar la verificación del certificado SSL
    • En Archivo > Configuración ( pestaña General ), desactive la verificación del certificado SSL . AdvertenciaVuelva a habilitar la verificación del certificado SSL después de probar el controlador.

Probar PostTodoItem con Postman

  • Crea una nueva solicitud.
  • Establezca el método HTTP en POST.
  • Establezca el URI en https://localhost:<port>/api/TodoItems. Por ejemplo https://localhost:5001/api/TodoItems,.
  • Seleccione la pestaña Cuerpo .
  • Seleccione la prima botón de radio.
  • Establezca el tipo en JSON (aplicación / json) .
  • En el cuerpo de la solicitud, ingrese JSON para una tarea pendiente:JSONDupdo{ "name":"walk dog", "isComplete":true }
  • Seleccione Enviar .

Prueba el URI del encabezado de ubicación

El URI del encabezado de ubicación se puede probar en el navegador. Copie y pegue el URI del encabezado de la ubicación en el navegador.

Para probar en Postman:

  • Seleccione la pestaña Encabezados en el panel Respuesta .
  • Copie el valor del encabezado de la ubicación :
  • Establezca el método HTTP en GET.
  • Establezca el URI en https://localhost:<port>/api/TodoItems/1. Por ejemplo https://localhost:5001/api/TodoItems/1,.
  • Seleccione Enviar .

Examine los métodos GET

Se implementan dos puntos finales GET:

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

Pruebe la aplicación llamando a los dos puntos finales desde un navegador o Postman. Por ejemplo:

  • https://localhost:5001/api/TodoItems
  • https://localhost:5001/api/TodoItems/1

La llamada a GetTodoItems: produce una respuesta similar a la siguiente :JSONDupdo

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

Prueba Get with Postman

  • Crea una nueva solicitud.
  • Establezca el método HTTP en GET .
  • Establezca el URI de la solicitud en https://localhost:<port>/api/TodoItems. Por ejemplo https://localhost:5001/api/TodoItems,.
  • Establezca la vista de dos paneles en Postman.
  • Seleccione Enviar .

Esta aplicación utiliza una base de datos en memoria. Si la aplicación se detiene e inicia, la solicitud GET anterior no devolverá ningún dato. Si no se devuelven datos, POST los datos a la aplicación.

Rutas de enrutamiento y URL

El [HttpGet]atributo denota un método que responde a una solicitud HTTP GET. La ruta URL para cada método se construye de la siguiente manera:

  • Comience con la cadena de plantilla en el Routeatributo del controlador :C#Dupdo[Route("api/[controller]")] [ApiController] public class TodoItemsController : ControllerBase { private readonly TodoContext _context; public TodoItemsController(TodoContext context) { _context = context; }
  • Reemplácelo [controller]con el nombre del controlador, que por convención es el nombre de la clase del controlador menos el sufijo “Controlador”. Para esta muestra, el nombre de la clase del controlador es TodoItems Controller, por lo que el nombre del controlador es “TodoItems”. El enrutamiento de ASP.NET Core no distingue entre mayúsculas y minúsculas.
  • Si el [HttpGet]atributo tiene una plantilla de ruta (por ejemplo, [HttpGet("products")]), agréguela a la ruta. Esta muestra no usa una plantilla. Para obtener más información, consulte Enrutamiento de atributos con atributos Http [Verb] .

En el siguiente GetTodoItemmétodo, "{id}"es una variable de marcador de posición para el identificador único de la tarea pendiente. Cuando GetTodoItemse invoca, el valor de "{id}"en la URL se proporciona al método en su idparámetro.C#Dupdo

// 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 devueltos

El tipo de retorno de los métodos GetTodoItemsGetTodoItemes el tipo ActionResult <T> . ASP.NET Core serializa automáticamente el objeto en JSON y escribe el JSON en el cuerpo del mensaje de respuesta. El código de respuesta para este tipo de retorno es 200 OK , asumiendo que no hay excepciones no controladas. Las excepciones no controladas se traducen en errores 5xx.

ActionResultLos tipos de retorno pueden representar una amplia gama de códigos de estado HTTP. Por ejemplo, GetTodoItempuede devolver dos valores de estado diferentes:

  • Si ningún elemento coincide con el ID solicitado, el método devuelve un código de error NotFound de estado 404 .
  • De lo contrario, el método devuelve 200 con un cuerpo de respuesta JSON. La devolución itemda como resultado una respuesta HTTP 200.

El método PutTodoItem

Examine el PutTodoItemmétodo:C#Dupdo

// 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();
}

PutTodoItemes similar a PostTodoItem, excepto que usa HTTP PUT. La respuesta es 204 (Sin contenido) . Según la especificación HTTP, una solicitud PUT requiere que el cliente envíe toda la entidad actualizada, no solo los cambios. Para admitir actualizaciones parciales, use HTTP PATCH .

Si recibe una llamada de error PutTodoItem, llame GETpara asegurarse de que haya un elemento en la base de datos.

Pruebe el método PutTodoItem

Esta muestra usa una base de datos en memoria que debe inicializarse cada vez que se inicia la aplicación. Debe haber un elemento en la base de datos antes de realizar una llamada PUT. Llame a GET para asegurarse de que haya un elemento en la base de datos antes de realizar una llamada PUT.

Actualice la tarea pendiente que tiene Id = 1 y establezca su nombre en "feed fish":JSONDupdo

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

La siguiente imagen muestra la actualización de Postman:

Consola del cartero que muestra la respuesta 204 (sin contenido)

El método DeleteTodoItem

Examine el DeleteTodoItemmétodo:C#Dupdo

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

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

    return NoContent();
}

Pruebe el método DeleteTodoItem

Utilice Postman para eliminar una tarea pendiente:

  • Establezca el método en DELETE.
  • Establezca el URI del objeto a eliminar (por ejemplo https://localhost:5001/api/TodoItems/1).
  • Seleccione Enviar .

Evitar la publicación excesiva

Actualmente, la aplicación de muestra expone todo el TodoItemobjeto. Las aplicaciones de producción suelen limitar los datos que se ingresan y devuelven mediante un subconjunto del modelo. Hay varias razones detrás de esto y la seguridad es una de las principales. El subconjunto de un modelo generalmente se denomina Objeto de transferencia de datos (DTO), modelo de entrada o modelo de vista. En este artículo se utiliza DTO .

Un DTO se puede utilizar para:

  • Evite la publicación excesiva.
  • Ocultar propiedades que los clientes no deben ver.
  • Omita algunas propiedades para reducir el tamaño de la carga útil.
  • Aplanar gráficos de objetos que contienen objetos anidados. Los gráficos de objetos aplanados pueden ser más convenientes para los clientes.

Para demostrar el enfoque DTO, actualice la TodoItemclase para incluir un campo secreto:C#Dupdo

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

El campo secreto debe estar oculto para esta aplicación, pero una aplicación administrativa podría optar por exponerlo.

Verifique que pueda publicar y obtener el campo secreto.

Cree un modelo DTO:C#Dupdo

public class TodoItemDTO
{
    public long Id { get; set; }
    public string Name { get; set; }
    public bool IsComplete { get; set; }
}

Actualice el TodoItemsControllerpara usar TodoItemDTO:C#Dupdo

// GET: api/TodoItems
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
{
    return await _context.TodoItems
        .Select(x => ItemToDTO(x))
        .ToListAsync();
}

[HttpGet("{id}")]
public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

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

    return ItemToDTO(todoItem);
}

[HttpPut("{id}")]
public async Task<IActionResult> UpdateTodoItem(long id, TodoItemDTO todoItemDTO)
{
    if (id != todoItemDTO.Id)
    {
        return BadRequest();
    }

    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    todoItem.Name = todoItemDTO.Name;
    todoItem.IsComplete = todoItemDTO.IsComplete;

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

    return NoContent();
}

[HttpPost]
public async Task<ActionResult<TodoItemDTO>> CreateTodoItem(TodoItemDTO todoItemDTO)
{
    var todoItem = new TodoItem
    {
        IsComplete = todoItemDTO.IsComplete,
        Name = todoItemDTO.Name
    };

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

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

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

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

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

    return NoContent();
}

private bool TodoItemExists(long id) =>
     _context.TodoItems.Any(e => e.Id == id);

private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
    new TodoItemDTO
    {
        Id = todoItem.Id,
        Name = todoItem.Name,
        IsComplete = todoItem.IsComplete
    };

Verifique que no pueda publicar ni obtener el campo secreto.

Llame a la API web con JavaScript

Agregar soporte de autenticación a una API web 2.1

ASP.NET Core Identity agrega la funcionalidad de inicio de sesión de la interfaz de usuario (UI) a las aplicaciones web ASP.NET Core. Para proteger las API web y las SPA, utilice uno de los siguientes:

IdentityServer4 es un marco OpenID Connect y OAuth 2.0 para ASP.NET Core. IdentityServer4 habilita las siguientes características de seguridad:

  • Autenticación como servicio (AaaS)
  • Inicio y cierre de sesión único (SSO) en varios tipos de aplicaciones
  • Control de acceso para API
  • Puerta de enlace de la federación

Para obtener más información, consulte Bienvenido a IdentityServer4 .

Te esperamos en los siguientes artículos en donde hablaremos mas acerca de estos temas, los cuales hoy en día son de vital importancia en el mundo de la tecnología.

¿Te gustaría aprender ASP.NET Core Empresarial?
Tenemos lo que necesitas .¡Haz clic aquí!

About Author

NGuerrero

Post Anterior

0 0 votos
Article Rating
Suscribir
Notificar de
guest
0 Comments
Comentarios.
Ver todos los comentarios
0
¿Te gusta este articulo? por favor comentax
()
x
Abrir chat
¿Quieres aprender a programar?
Hola 👋,
¿Te interesa información de nuestros cursos?