En este post se procederá a explicar cómo leer archivos JSON y los respectivos objetos con LINQ (para las consultas) en .Net Core (más concretamente: ASP.NET Core Web App [MVC 6.0]).

Una vez creado un nuevo proyecto será primordial la instalación del tan conocido NuGet en la última versión: ‘Newtonsoft.Json‘, ya que es necesario para manipular los datos JSON y el propio uso de LINQ para ello.

Para ello se hace click derecho sobre la solución (el proyecto) y se selecciona Manage NuGet Packages…, ahí se accede a buscar y se escribe el NuGet. Si se instala satisfactoriamente aparecerá en la pestaña de instalados.

Nota: El primer NuGet (CodeGeneration.Design) se genera al hacer vistas scaffolding, así que no es necesario que lo tengáis salvo que lo uséis (y se instala automáticamente).

La estructura recomendada para el proyecto y que yo uso es la siguiente:

En wwwroot se crea la carpeta documents y se introduce el archivo JSON con todos sus objetos. En este caso yo uso uno en el que muestro películas (y adicionalmente series).

{
  "peliculas": [
    {
      "id": 1,
      "titulo": "El caballero oscuro",
      "director": "Christopher Nolan",
      "fecha": 2008,
      "duracion": 152,
      "genero": "Acción",
      "descripcion": "Batman/Bruce Wayne (Christian Bale) regresa para continuar su guerra contra el crimen. Con la ayuda del teniente Jim Gordon (Gary Oldman) y del Fiscal del Distrito Harvey Dent (Aaron Eckhart), Batman se propone destruir el crimen organizado en la ciudad de Gotham. El triunvirato demuestra su eficacia, pero, de repente, aparece Joker (Heath Ledger), un nuevo criminal que desencadena el caos y tiene aterrados a los ciudadanos.",
      "poster": "https://pics.filmaffinity.com/the_dark_knight-102763119-mmed.jpg",
      "fondo": "https://media.revistagq.com/photos/5dd57f2742317f0008ff2f7b/master/w_1920,h_1148,c_limit/caballero%20oscuro.jpg"
    },
    {
      "id": 2,
      "titulo": "Joker",
      "director": "Todd Phillips",
      "fecha": 2019,
      "duracion": 121,
      "genero": "Thriller",
      "descripcion": "Arthur Fleck (Phoenix) vive en Gotham con su madre, y su única motivación en la vida es hacer reír a la gente. Actúa haciendo de payaso en pequeños trabajos, pero tiene problemas mentales que hacen que la gente le vea como un bicho raro. Su gran sueño es actuar como cómico delante del público, pero una serie de trágicos acontecimientos le hará ir incrementando su ira contra una sociedad que le ignora.",
      "poster": "https://pics.filmaffinity.com/joker-790658206-mmed.jpg",
      "fondo": "https://media.revistavanityfair.es/photos/60e83c8283a12578074964b5/master/pass/179268.jpg"
    },
    {
      "id": 3,
      "titulo": "Whiplash",
      "director": "Damien Chazelle",
      "fecha": 2014,
      "duracion": 103,
      "genero": "Drama",
      "descripcion": "El objetivo de Andrew Neiman (Miles Teller), un joven y ambicioso baterista de jazz, es triunfar en el elitista Conservatorio de Música de la Costa Este. Marcado por el fracaso de la carrera literaria de su padre, Andrew alberga sueños de grandeza. Terence Fletcher (J.K. Simmons), un profesor conocido tanto por su talento como por sus rigurosos métodos de enseñanza, dirige el mejor conjunto de jazz del Conservatorio. Cuando Fletcher elige a Andrew para formar parte del grupo, la vida del joven cambiará.",
      "poster": "https://pics.filmaffinity.com/whiplash-344887410-mmed.jpg",
      "fondo": "https://www.noticiasbarquisimeto.com/wp-content/uploads/2022/06/327ea5e385bbc40527787770871ebbf0-696x392.png"
    },
    {
      "id": 4,
      "titulo": "Pulp Fiction",
      "director": "Quentin Tarantino",
      "fecha": 1994,
      "duracion": 153,
      "genero": "Drama",
      "descripcion": "Jules y Vincent, dos asesinos a sueldo con no demasiadas luces, trabajan para el gángster Marsellus Wallace. Vincent le confiesa a Jules que Marsellus le ha pedido que cuide de Mia, su atractiva mujer. Jules le recomienda prudencia porque es muy peligroso sobrepasarse con la novia del jefe. Cuando llega la hora de trabajar, ambos deben ponerse 'manos a la obra'. Su misión: recuperar un misterioso maletín.",
      "poster": "https://pics.filmaffinity.com/pulp_fiction-210382116-mmed.jpg",
      "fondo": "https://media.timeout.com/images/101749805/image.jpg"
    },
    {
      "id": 5,
      "titulo": "El lobo de Wall Street",
      "director": "Martin Scorsese",
      "fecha": 2013,
      "duracion": 179,
      "genero": "Comedia",
      "descripcion": "A mediados de los años 80, Belfort era un joven honrado que perseguía el sueño americano, pero pronto en la agencia de valores aprendió que lo más importante no era hacer ganar a sus clientes, sino ser ambicioso y ganar una buena comisión. Su enorme éxito y fortuna le valió el mote de “El lobo de Wall Street”. Dinero. Poder. Mujeres. Drogas. Las tentaciones abundaban y el temor a la ley era irrelevante. Jordan y su manada de lobos consideraban que la discreción era una cualidad anticuada; nunca se conformaban con lo que tenían.",
      "poster": "https://pics.filmaffinity.com/the_wolf_of_wall_street-675195906-mmed.jpg",
      "fondo": "https://filmhafizasi.com/wp-content/uploads/2022/02/wolf-3.jpg"
    },
    {
      "id": 6,
      "titulo": "Drive",
      "director": "Nicolas Winding Refn",
      "fecha": 2011,
      "duracion": 100,
      "genero": "Acción",
      "descripcion": "Durante el día, Driver (Ryan Gosling) trabaja en un taller y es conductor especialista de cine, pero, algunas noches de forma esporádica, trabaja como chófer para delincuentes. Shannon, su jefe, que conoce bien su talento al volante, lo mismo le busca directores de cine y televisión que criminales que necesiten al mejor conductor para sus fugas, llevándose la correspondiente comisión. Pero el mundo de Driver comienza a cambiar el día en que conoce a Irene (Carey Mulligan), una guapa vecina que tiene un hijo pequeño y a su marido en la cárcel.",
      "poster": "https://pics.filmaffinity.com/drive-467825966-mmed.jpg",
      "fondo": "https://occ-0-1723-3211.1.nflxso.net/dnm/api/v6/E8vDc_W8CLv7-yMQu8KMEC7Rrr8/AAAABUK8Dc-eM8Cte0Xph23wu5KY1FNJGqDHXDkzitVuurpniwYp9GlMQ64N0Tp7Ka9vcSpQ0RvKpRIVjikSwrLeq4NTukfuABhMWZrl.jpg?r=2f7"
    },
    {
      "id": 7,
      "titulo": "Nightcrawler",
      "director": "Dan Gilroy",
      "fecha": 2014,
      "duracion": 113,
      "genero": "Thriller",
      "descripcion": "Tras ser testigo de un accidente, Lou Bloom (Jake Gyllenhaal), un apasionado joven que no consigue encontrar empleo, descubre como forma de ganar dinero el mundo del periodismo criminalista en la peligrosa ciudad de Los Ángeles. Su trabajo es llegar al escenario de crímenes o accidentes y fotografiar lo sucedido para venderlos al mejor postor.",
      "poster": "https://pics.filmaffinity.com/nightcrawler-317347366-mmed.jpg",
      "fondo": "https://ichef.bbci.co.uk/images/ic/1200x675/p082bgzd.jpg"
    },
    {
      "id": 8,
      "titulo": "Avatar",
      "director": "James Cameron",
      "fecha": 2009,
      "duracion": 161,
      "genero": "Ciencia ficción",
      "descripcion": "Año 2154. Jake Sully (Sam Worthington), un ex-marine condenado a vivir en una silla de ruedas, sigue siendo, a pesar de ello, un auténtico guerrero. Precisamente por ello ha sido designado para ir a Pandora, donde algunas empresas están extrayendo un mineral extraño que podría resolver la crisis energética de la Tierra. Para contrarrestar la toxicidad de la atmósfera de Pandora, se ha creado el programa Avatar, gracias al cual los seres humanos mantienen sus conciencias unidas a un avatar: un cuerpo biológico controlado de forma remota que puede sobrevivir en el aire letal.",
      "poster": "https://pics.filmaffinity.com/avatar-208925608-mmed.jpg",
      "fondo": "https://cdn.computerhoy.com/sites/navi.axelspringer.es/public/media/image/2021/06/avatar-2366079.jpg"
    }
  ],
  "series": [
    {
      "id": 1,
      "titulo": "Breaking Bad",
      "temporadas": 5,
      "episodios": 62,
      "fecha": 2008,
      "duracion": 45,
      "genero": "Thriller",
      "poster": "https://pics.filmaffinity.com/breaking_bad-504442815-mmed.jpg"
    },
    {
      "id": 2,
      "titulo": "Juego de Tronos",
      "temporadas": 8,
      "episodios": 73,
      "fecha": 2011,
      "duracion": 55,
      "genero": "Aventura",
      "poster": "https://pics.filmaffinity.com/game_of_thrones-293142110-mmed.jpg"
    },
    {
      "id": 3,
      "titulo": "Los Soprano",
      "temporadas": 6,
      "episodios": 86,
      "fecha": 1999,
      "duracion": 50,
      "genero": "Thriller",
      "poster": "https://pics.filmaffinity.com/the_sopranos-196243243-mmed.jpg"
    },
    {
      "id": 4,
      "titulo": "True Detective",
      "temporadas": 1,
      "episodios": 8,
      "fecha": 2014,
      "duracion": 60,
      "genero": "Drama",
      "poster": "https://pics.filmaffinity.com/true_detective-799068355-mmed.jpg"
    },
    {
      "id": 5,
      "titulo": "Friends",
      "temporadas": 10,
      "episodios": 236,
      "fecha": 1994,
      "duracion": 20,
      "genero": "Comedia",
      "poster": "https://pics.filmaffinity.com/friends-344732706-mmed.jpg"
    },
    {
      "id": 6,
      "titulo": "Peaky Blinders",
      "temporadas": 6,
      "episodios": 36,
      "fecha": 2013,
      "duracion": 60,
      "genero": "Drama",
      "poster": "https://pics.filmaffinity.com/peaky_blinders-713495787-mmed.jpg"
    },
    {
      "id": 7,
      "titulo": "Narcos",
      "temporadas": 3,
      "episodios": 30,
      "fecha": 2015,
      "duracion": 52,
      "genero": "Drama",
      "poster": "https://pics.filmaffinity.com/narcos-320030424-mmed.jpg"
    },
    {
      "id": 8,
      "titulo": "Lost",
      "temporadas": 6,
      "episodios": 121,
      "fecha": 2004,
      "duracion": 42,
      "genero": "Aventura",
      "poster": "https://pics.filmaffinity.com/lost-924104956-mmed.jpg"
    }
  ]
}

Tenemos los controladores, los modelos y las vistas. También se añade el repositorio que tendrá almacenados todos los métodos y el uso de LINQ y el helper para poder encontrar la ruta del archivo donde se encuentra almacenado.

Se tiene que crear el modelo de película con los diferentes atributos existentes en el archivo JSON para su posterior uso:

namespace JsonToLinqProject.Models
{
    public class Pelicula
    {
        public int Id { get; set; }
        public string Titulo { get; set; }
        public string Director { get; set; }
        public int Fecha { get; set; }
        public int Duracion { get; set; }
        public string Genero { get; set; }
        public string Descripcion { get; set; }
        public string Poster { get; set; }
        public string Fondo { get; set; }
    }
}

El helper resolverá con el uso de ‘environment’ y el método la ruta en la que se encontrá el documento más adelante.

namespace JsonToLinqProject.Helpers
{
    public enum Folders { Images = 0, Documents = 1 }
    public class HelperPathProvider
    {
        private IWebHostEnvironment environment;

        public HelperPathProvider(IWebHostEnvironment environment)
        {
            this.environment = environment;
        }

        public string MapPath(string fileName, Folders folder)
        {
            string carpeta = "";
            if (folder == Folders.Images)
            {
                carpeta = "images";
            }
            else if (folder == Folders.Documents)
            {
                carpeta = "documents";
            }
            string path = Path.Combine(this.environment.WebRootPath, carpeta, fileName);
            return path;
        }
    }
}

Lo siguiente será en el repositorio establecer la ruta del documento mediante el helper y el método (MapPath). Esto se hará dentro del constructor.

Y ya tendremos los métodos para obtener la lista de películas, una película; crear una película, editarla o borrarla.

En todos los métodos se tendrá que leer el archivo con ‘File.ReadAllText’ y su ruta. Posteriormente se hace ‘parsing’ a objeto del archivo y del objeto nuevamente a una lista comoa array en la que se recorre para obtener uno a uno todos los elementos.

Para encontrar una sola película mediante LINQ se elige el primer elemento en base al ID que se le pasa por parámetro y si no hay se retorna nulo.

Para crear las películas se obtienen todos los parámetros mediante formulario. Se establece un nuevo id siguiente al último que haya y se establecen los parámetros al nuevo objeto. Finalmente solo se añade el nuevo a la lista.

Para actualizar una película se obtendrán los valores, al igual que en la creación, mediante un formulario y se obtendrá el id con un input de tipo ‘hidden’. En base a ese índice y los parámetros se actualizará la película.

Por último, para borrar se obtiene el id de la película y se borra de la lista con ‘removeAt’.

using JsonToLinqProject.Helpers;
using JsonToLinqProject.Models;
using Newtonsoft.Json.Linq;

namespace JsonToLinqProject.Repositories
{
    public class RepositoryJSON
    {
        private HelperPathProvider helper;
        private string pathPelisyseries;

        public RepositoryJSON(HelperPathProvider helper)
        {
            this.helper = helper;
            this.pathPelisyseries = this.helper.MapPath("pelisyseries.json", Folders.Documents);
        }

        public List<Pelicula> GetPeliculas()
        {
            List<Pelicula> peliculas = new List<Pelicula>();
            string json = File.ReadAllText(this.pathPelisyseries);
            JObject jObject = JObject.Parse(json);
            JArray jArray = (JArray)jObject["peliculas"];
            foreach (JObject jPelicula in jArray)
            {
                Pelicula pelicula = new Pelicula();
                pelicula.Id = (int)jPelicula["id"];
                pelicula.Titulo = (string)jPelicula["titulo"];
                pelicula.Director = (string)jPelicula["director"];
                pelicula.Fecha = (int)jPelicula["fecha"];
                pelicula.Duracion = (int)jPelicula["duracion"];
                pelicula.Genero = (string)jPelicula["genero"];
                pelicula.Descripcion = (string)jPelicula["descripcion"];
                pelicula.Poster = (string)jPelicula["poster"];
                pelicula.Fondo = (string)jPelicula["fondo"];
                peliculas.Add(pelicula);
            }
            return peliculas;
        }

        public Pelicula FindPelicula(int idpelicula)
        {
            string json = File.ReadAllText(this.pathPelisyseries);
            JObject jObject = JObject.Parse(json);
            JArray jArray = (JArray)jObject["peliculas"];
            JObject jPelicula = (JObject)jArray.FirstOrDefault(p => (int)p["id"] == idpelicula);
            if (jPelicula != null)
            {
                Pelicula pelicula = new Pelicula();
                pelicula.Id = (int)jPelicula["id"];
                pelicula.Titulo = (string)jPelicula["titulo"];
                pelicula.Director = (string)jPelicula["director"];
                pelicula.Fecha = (int)jPelicula["fecha"];
                pelicula.Duracion = (int)jPelicula["duracion"];
                pelicula.Genero = (string)jPelicula["genero"];
                pelicula.Descripcion = (string)jPelicula["descripcion"];
                pelicula.Poster = (string)jPelicula["poster"];
                pelicula.Fondo = (string)jPelicula["fondo"];
                return pelicula;
            }
            else
            {
                return null;
            }
        }

        public void CreatePelicula(string titulo, string director, int fecha, int duracion, string genero, string descripcion, string poster, string fondo)
        {
            string json = File.ReadAllText(this.pathPelisyseries);
            JObject jObject = JObject.Parse(json);
            JArray jArray = (JArray)jObject["peliculas"];

            int maxId = jArray.Max(p => (int)p["id"]);
            int idpelicula = maxId + 1;

            JObject newJPelicula = new JObject(
                new JProperty("id", idpelicula),
                new JProperty("titulo", titulo),
                new JProperty("director", director),
                new JProperty("fecha", fecha),
                new JProperty("duracion", duracion),
                new JProperty("genero", genero),
                new JProperty("descripcion", descripcion),
                new JProperty("poster", poster),
                new JProperty("fondo", fondo)
            );

            jArray.Add(newJPelicula);
            jObject["peliculas"] = jArray;
            File.WriteAllText(this.pathPelisyseries, jObject.ToString());
        }

        public void UpdatePelicula(int idpelicula, string titulo, string director, int fecha, int duracion, string genero, string descripcion, string poster, string fondo)
        {
            string json = File.ReadAllText(this.pathPelisyseries);
            JObject jObject = JObject.Parse(json);
            JArray jArray = (JArray)jObject["peliculas"];

            int index = jArray.IndexOf(jArray.FirstOrDefault(p => (int)p["id"] == idpelicula));

            jArray[index]["titulo"] = titulo;
            jArray[index]["director"] = director;
            jArray[index]["fecha"] = fecha;
            jArray[index]["duracion"] = duracion;
            jArray[index]["genero"] = genero;
            jArray[index]["descripcion"] = descripcion;
            jArray[index]["poster"] = poster;
            jArray[index]["fondo"] = fondo;

            jObject["peliculas"] = jArray;
            File.WriteAllText(this.pathPelisyseries, jObject.ToString());
        }

        public void DeletePelicula(int id)
        {
            string json = File.ReadAllText(this.pathPelisyseries);
            JObject jObject = JObject.Parse(json);
            JArray jArray = (JArray)jObject["peliculas"];

            int index = jArray.IndexOf(jArray.FirstOrDefault(p => (int)p["id"] == id));

            jArray.RemoveAt(index);
            jObject["peliculas"] = jArray;
            File.WriteAllText(this.pathPelisyseries, jObject.ToString());
        }
    }
}

Hecho el repositorio es importante en Program.cs instanciar los servicios:

// Add services to the container.
builder.Services.AddSingleton<HelperPathProvider>();
builder.Services.AddTransient<RepositoryJSON>();
builder.Services.AddControllersWithViews();

Con esto finalizado solo quedará el controlador de las películas y sus respectivas vistas.

Para el controller (PeliculasController) se aplica el repositorio dentro del constructor.

Para las diferentes vistas se usan los métodos del repositorio que se veían previamente. El HttpPost también en el caso de crear y actualizar una película, ya que se usa formulario.

using JsonToLinqProject.Models;
using JsonToLinqProject.Repositories;
using Microsoft.AspNetCore.Mvc;

namespace JsonToLinqProject.Controllers
{
    public class PeliculasController : Controller
    {
        private RepositoryJSON repo;

        public PeliculasController(RepositoryJSON repo)
        {
            this.repo = repo;
        }

        public IActionResult Index()
        {
            List<Pelicula> peliculas = this.repo.GetPeliculas();
            return View(peliculas);
        }

        public IActionResult Details(int idpelicula)
        {
            Pelicula pelicula = this.repo.FindPelicula(idpelicula);
            return View(pelicula);
        }

        public IActionResult Delete(int idpelicula)
        {
            this.repo.DeletePelicula(idpelicula);
            return RedirectToAction("Index");
        }

        public IActionResult Update(int idpelicula)
        {
            Pelicula pelicula = this.repo.FindPelicula(idpelicula);
            return View(pelicula);
        }

        [HttpPost]
        public IActionResult Update(Pelicula pelicula)
        {
            this.repo.UpdatePelicula(pelicula.Id, pelicula.Titulo, pelicula.Director, pelicula.Fecha, pelicula.Duracion, pelicula.Genero, pelicula.Descripcion, pelicula.Poster, pelicula.Fondo);
            return RedirectToAction("Index");
        }

        public IActionResult Create()
        {
            return View();
        }

        [HttpPost]
        public IActionResult Create(Pelicula pelicula)
        {
            this.repo.CreatePelicula(pelicula.Titulo, pelicula.Director, pelicula.Fecha, pelicula.Duracion, pelicula.Genero, pelicula.Descripcion, pelicula.Poster, pelicula.Fondo);
            return RedirectToAction("Index");
        }
    }
}

Para las vistas le agregamos en el modelo lo que se devuelve en el controlador a las vistas. Por ejemplo, para películas la List<Pelicula>. Y también está bien agregarle algo de estilo (+ se puede generar scaffolding también sin problema).

El index:

@model List<Pelicula>

<div class="text-center mt-4" style="margin-bottom: -3em !important;">
    <a asp-controller="Peliculas" asp-action="Create" class="btn btn-secondary m-auto">
        Crear película
    </a>
</div>

@foreach (Pelicula pelicula in Model)
{
    <div class="movie_card" id="bright">
        <div class="info_section">
            <div class="movie_edit">
                <ul>
                    <li><a asp-controller="Peliculas" asp-action="Update" asp-route-idpelicula="@pelicula.Id"><i class="fa-solid fa-pen-to-square"></i></a></li>
                    <li><a asp-controller="Peliculas" asp-action="Delete" asp-route-idpelicula="@pelicula.Id"><i class="fa-solid fa-trash" style="color: darkred;" onmouseout="this.style.color='darkred'" onmouseover="this.style.color='#FFC107'"></i></a></li>
                </ul>
            </div>
            <div class="movie_header">
                <img class="locandina" src="@pelicula.Poster" />
                <h1>@pelicula.Titulo</h1>
                <h4>@pelicula.Fecha, @pelicula.Director</h4>
                <span class="minutes">@pelicula.Duracion min.</span>
                <p class="type">@pelicula.Genero</p>
            </div>
            <div class="movie_desc">
                <p class="text">
                    @pelicula.Descripcion
                </p>
            </div>
            <div class="movie_social">
                <ul>
                    <li><i class="fa-solid fa-share-nodes"></i></li>
                    <li><i class="fa-solid fa-heart"></i></li>
                    <li><i class="fa-solid fa-message"></i></li>
                </ul>
            </div>
        </div>
        <div class="blur_back" style="background: url(@pelicula.Fondo);">
        </div>
    </div>
}

<style>

    .link {
        display: block;
        text-align: center;
        color: #777;
        text-decoration: none;
        padding: 10px;
    }

    .movie_card {
        position: relative;
        display: block;
        max-width: 1000px;
        height: 450px;
        margin: 80px auto;
        overflow: hidden;
        border-radius: 10px;
        transition: all 0.4s;
        box-shadow: 0px 0px 120px -25px rgba(0, 0, 0, 0.5);
    }

        .movie_card:hover {
            transform: scale(1.02);
            box-shadow: 0px 0px 80px -25px rgba(0, 0, 0, 0.5);
            transition: all 0.4s;
        }

        .movie_card .info_section {
            position: relative;
            width: 100%;
            height: 100%;
            background-blend-mode: multiply;
            z-index: 2;
            border-radius: 10px;
        }

            .movie_card .info_section .movie_header {
                position: relative;
                padding: 25px;
                height: 40%;
            }

                .movie_card .info_section .movie_header h1 {
                    color: black;
                    font-weight: 400;
                }

                .movie_card .info_section .movie_header h4 {
                    color: #555;
                    font-weight: 400;
                }

                .movie_card .info_section .movie_header .minutes {
                    display: inline-block;
                    margin-top: 15px;
                    color: #555;
                    padding: 5px;
                    border-radius: 5px;
                    border: 1px solid rgba(0, 0, 0, 0.05);
                }

                .movie_card .info_section .movie_header .type {
                    display: inline-block;
                    color: #959595;
                    margin-left: 10px;
                }

                .movie_card .info_section .movie_header .locandina {
                    position: relative;
                    float: left;
                    margin-right: 20px;
                    height: 120px;
                    box-shadow: 0 0 20px -10px rgba(0, 0, 0, 0.5);
                }

            .movie_card .info_section .movie_desc {
                padding-left: 25px;
                height: 50%;
            }

                .movie_card .info_section .movie_desc .text {
                    color: #545454;
                }

            .movie_card .info_section .movie_social {
                height: 10%;
                padding-left: 15px;
                padding-bottom: 20px;
            }

                .movie_card .info_section .movie_social ul {
                    list-style: none;
                    padding: 0;
                }

                    .movie_card .info_section .movie_social ul li {
                        display: inline-block;
                        color: rgba(0, 0, 0, 0.3);
                        transition: color 0.3s;
                        transition-delay: 0.15s;
                        margin: 0 10px;
                    }

                        .movie_card .info_section .movie_social ul li:hover {
                            transition: color 0.3s;
                            color: rgba(0, 0, 0, 0.7);
                        }

                        .movie_card .info_section .movie_social ul li i {
                            font-size: 19px;
                            cursor: pointer;
                        }

        .movie_card .movie_edit {
            position: absolute;
            top: 10px;
            right: 10px;
            z-index: 3;
        }

            .movie_card .movie_edit ul {
                display: flex;
                justify-content: space-between;
                list-style: none;
                padding: 0;
                margin: 0;
            }

                .movie_card .movie_edit ul li {
                    display: inline-block;
                    transition: color 0.3s;
                    transition-delay: 0.15s;
                    margin: 0 10px;
                }

                .movie_card .movie_edit ul li {
                    margin: 0 5px;
                    display: inline-block;
                }

                    .movie_card .movie_edit ul li a {
                        font-size: 19px;
                        color: darkorange !important;
                    }

                        .movie_card .movie_edit ul li a:hover {
                            color: #FFC107 !important;
                        }

        .movie_card .blur_back {
            position: absolute;
            top: 0;
            z-index: 1;
            height: 100%;
            right: 0;
            border-radius: 11px;
        }

    @@media screen and (min-width: 992px) {
        .movie_header {
            width: 65%;
            white-space: nowrap !important;
        }

        .movie_desc {
            width: 50%;
        }

        .info_section {
            background: linear-gradient(to right, #e5e6e6 50%, transparent 100%);
        }

        .blur_back {
            width: 100%;
            background-position: 175% 0% !important;
            background-size: contain !important;
        }
    }

    @@media screen and (max-width: 992px) {
        .movie_card {
            width: 95%;
            margin: 70px auto;
            min-height: 350px;
            height: auto;
        }

        .blur_back {
            width: 100%;
            background-position: 0% 0% !important;
            background-size: contain !important;
        }

        .movie_header {
            width: 100%;
            margin-top: 85px;
            white-space: normal !important;
        }

        .movie_desc {
            width: 100%;
        }

        .info_section {
            background: linear-gradient(to top, #e5e6e6 50%, transparent 100%);
            display: inline-grid;
        }
    }

    @@media screen and (max-width: 450px) {
        .movie_card .blur_back {
            height: 50% !important;
        }

        .blur_back {
            width: 100%;
            background-position: 50% 0% !important;
            background-size: cover !important;
        }
    }
</style>

Crear la película:

@model JsonToLinqProject.Models.Pelicula

@{
    ViewData["Title"] = "Create";
}

<h4>Crear película</h4>
<hr />
<div class="row d-flex justify-content-center">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Titulo" class="control-label"></label>
                <input asp-for="Titulo" class="form-control" />
                <span asp-validation-for="Titulo" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Director" class="control-label"></label>
                <input asp-for="Director" class="form-control" />
                <span asp-validation-for="Director" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Fecha" class="control-label"></label>
                <input asp-for="Fecha" class="form-control" />
                <span asp-validation-for="Fecha" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Duracion" class="control-label"></label>
                <input asp-for="Duracion" class="form-control" />
                <span asp-validation-for="Duracion" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Genero" class="control-label"></label>
                <input asp-for="Genero" class="form-control" />
                <span asp-validation-for="Genero" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Descripcion" class="control-label"></label>
                <input asp-for="Descripcion" class="form-control" />
                <span asp-validation-for="Descripcion" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Poster" class="control-label"></label>
                <input asp-for="Poster" class="form-control" />
                <span asp-validation-for="Poster" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Fondo" class="control-label"></label>
                <input asp-for="Fondo" class="form-control" />
                <span asp-validation-for="Fondo" class="text-danger"></span>
            </div>
            <div class="form-group mt-4 mb-4">
                <input type="submit" value="Crear película" class="btn btn-secondary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Volver atrás</a>
</div>

@section Scripts {
    @{
        await Html.RenderPartialAsync("_ValidationScriptsPartial");
    }
}

Actualizar la película:

@model JsonToLinqProject.Models.Pelicula

@{
    ViewData["Title"] = "Update";
}

<h4>Actualizar película: @Model.Titulo</h4>
<hr />
<div class="row d-flex justify-content-center">
    <div class="col-md-4">
        <form asp-action="Update">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <label asp-for="Id" class="control-label"></label>
            <input type="hidden" asp-for="Id" class="form-control" />
            <div class="form-group">
                <label asp-for="Titulo" class="control-label"></label>
                <input asp-for="Titulo" class="form-control" />
                <span asp-validation-for="Titulo" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Director" class="control-label"></label>
                <input asp-for="Director" class="form-control" />
                <span asp-validation-for="Director" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Fecha" class="control-label"></label>
                <input asp-for="Fecha" class="form-control" />
                <span asp-validation-for="Fecha" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Duracion" class="control-label"></label>
                <input asp-for="Duracion" class="form-control" />
                <span asp-validation-for="Duracion" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Genero" class="control-label"></label>
                <input asp-for="Genero" class="form-control" />
                <span asp-validation-for="Genero" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Descripcion" class="control-label"></label>
                <input asp-for="Descripcion" class="form-control" />
                <span asp-validation-for="Descripcion" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Poster" class="control-label"></label>
                <input asp-for="Poster" class="form-control" />
                <span asp-validation-for="Poster" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Fondo" class="control-label"></label>
                <input asp-for="Fondo" class="form-control" />
                <span asp-validation-for="Fondo" class="text-danger"></span>
            </div>
            <div class="form-group mt-4 mb-4">
                <input type="submit" value="Guardar" class="btn btn-secondary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Volver atrás</a>
</div>

@section Scripts {
    @{
        await Html.RenderPartialAsync("_ValidationScriptsPartial");
    }
}

Generamos en el _Layout de _Shared un link que lleve a películas.

<li class="nav-item">
    <a class="nav-link text-white" asp-area="" asp-controller="Peliculas" asp-action="Index">Peliculas</a>
</li>

Y ya con esto estaría finalizado el proyecto con todas sus funcionalidades (muy ampliables) de forma dinámica.

Si todo está correcto así debería verse:

Autor: Andrei Garbea
Curso: Desarrollo Web Full Stack, MultiCloud y Multiplataforma
Centro: Tajamar
Año académico: 2022-2023
GithubEnlace a GitHub

Recursos:

https://www.newtonsoft.com/json/help/html/LINQtoJSON.htm

https://stackoverflow.com/questions/18758361/can-i-linq-a-json

Leave a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.