Crear una nueva clase de servicio

Anteriormente en el capítulo de conceptos básicos de MVC, creaste un FakeTodoItemService que contenía elementos de tareas pendientes codificados. Ahora que tiene un contexto de base de datos, puede crear una nueva clase de servicio que usará Entity Framework Core para obtener los tareas reales de la base de datos.

Elimine el archivo FakeTodoItemService.cs y cree un nuevo archivo:

Services/TodoItemService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AspNetCoreTodo.Data;
using AspNetCoreTodo.Models;
using Microsoft.EntityFrameworkCore;

namespace AspNetCoreTodo.Services
{
    public class TodoItemService : ITodoItemService
    {
        private readonly ApplicationDbContext _context;

        public TodoItemService(ApplicationDbContext context)
        {
            _context = context;
        }

        public async Task<TodoItem[]> GetIncompleteItemsAsync()
        {
            var items = await _context.Items
                .Where(x => x.IsDone == false)
                .ToArrayAsync();
            return items;
        }
    }
}

Notará el mismo patrón de inyección de dependencia aquí que vio en el capítulo Fundamentos de MVC, excepto que esta vez se está inyectando el ApplicationDbContext. El ApplicationDbContext ya se está agregando al contenedor de servicios en el método ConfigureServices, por lo que está disponible para inyección aquí.

Echemos un vistazo más de cerca al código del método GetIncompleteItemsAsync. Primero, usa la propiedad Items del contexto para acceder a todos los elementos de la tarea en el DbSet:

var items = await _context.Items

Luego, el método Where se usa para filtrar solo las tareas que no están completas:

.Where(x => x.IsDone == false)

El método Where es una característica de C # llamada LINQ (Lenguaje INtegrated Query), que se inspira en la programación funcional y facilita la expresión de consultas de base de datos en código. Bajo el capó, Entity Framework Core traduce el método Where en una declaración como SELECT * FROM Items WHERE IsDone = 0, o un documento de consulta equivalente en una base de datos NoSQL.

Finalmente, el método ToArrayAsync le dice a Entity Framework Core que obtenga todas las entidades que coincidan con el filtro y las devuelva como una matriz. El método ToArrayAsync es asíncrono (devuelve un Task), por lo que debe estar esperando await para obtener su valor.

Para que el método sea un poco más corto, puedes eliminar la variable intermedia items y simplemente devolver el resultado de la consulta directamente (que hace lo mismo):

public async Task<TodoItem[]> GetIncompleteItemsAsync()
{
    return await _context.Items
        .Where(x => x.IsDone == false)
        .ToArrayAsync();
}

Actualizar el contenedor de servicios

Debido a que eliminó la clase FakeTodoItemService, deberá actualizar la línea en ConfigureServices que está cableando la interfaz ITodoItemService:

services.AddScoped<ITodoItemService, TodoItemService>();

AddScoped agrega su servicio al contenedor de servicio utilizando el ciclo de vida de ámbito. Esto significa que se creará una nueva instancia de la clase TodoItemService durante cada solicitud web. Esto es necesario para las clases de servicio que interactúan con una base de datos.

Agregar una clase de servicio que interactúa con Entity Framework Core (y su base de datos) con el ciclo de vida de singleton (u otros ciclos de vida) puede causar problemas, debido a cómo Entity Framework Core administra las conexiones de base de datos por solicitud bajo el capó. Para evitarlo, utilice siempre el ciclo de vida con ámbito para los servicios que interactúan con Entity Framework Core.

¡El TodoController que depende de un ITodoItemService inyectado será maravillosamente inconsciente del cambio en las clases de servicios, pero bajo el capó estará usando Entity Framework Core y¡hablando con una base de datos real!

Pruébalo

Inicie la aplicación y navegue a http://localhost:5000/todo. Los tareas falsos se han ido y su aplicación está realizando consultas reales a la base de datos. No sucede que haya tareas pendientes guardados, por lo que está en blanco por ahora.

En el siguiente capítulo, agregará más funciones a la aplicación, comenzando con la capacidad de crear nuevos tareas pendientes.