Home > Software engineering >  ASP.NET MVC cannot parse a Http Get request into Json Model
ASP.NET MVC cannot parse a Http Get request into Json Model

Time:06-30

I am making a get request to a public themoviedb api via Http get request to get a List of Movies. My Movies Model:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace CSApp.Models;
using Newtonsoft.Json;

[Table("Movies")]
public class Movie
{
    public bool? adult { get; set; }
    public string? backdrop_path { get; set; }

    [JsonIgnore]
    [NotMapped]
    public IList<int>? genre_ids { get; set; }

    [Key]
    [Required]
    public int id;

    public string? original_language { get; set; }
    public string? original_title { get; set; }
    public string? overview { get; set; }
    public decimal? popularity { get; set; }
    public  string? poster_path { get; set;}

    [Column(TypeName = "datetime")]
    public DateTime? release_date { get; set;}
    public string? title{ get; set;}
    public bool? video { get; set; }
    public decimal? vote_average { get; set; }
    public int?  vote_count{ get; set;}
}

Make request goes to: https://api.themoviedb.org/3/discover/movie?api_key=XXXXXXXXXXXXXXXXXX

My Controller:

using System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using CSApp.Models;
using static System.Console;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace CSApp.Controllers;

//[ApiController]
//[Route("/api/[controller]")]
public class MovieController: Controller
{
    private ILogger<MovieController> _logger;
    private IHttpClientFactory _clientFactory;
    private readonly MovieDBContext _db;
    public MovieController( ILogger<MovieController> logger,
     IHttpClientFactory httpClientFactory, MovieDBContext db)
    {
           _logger = logger;
           _clientFactory = httpClientFactory;
            _db = db;
    }

    public IActionResult Index()
    {
        ViewData["Title"] = "Movies List";
        ViewData["DayName"] = DateTime.Now.ToString("dddd");
        IList<Movie> model = _db.DBMovies.ToList();        
        return View(model);
    }


    [HttpGet]
    [ProducesResponseType(200, Type = typeof(IEnumerable<Object>))]
    public async Task<IActionResult> Movies()
    {


        string api_key = "XXXXXXXXXXXX";
        string uri = $"discover/movie?api_key={api_key}";
        HttpClient client = _clientFactory.CreateClient("MoviesDBClient");


        HttpRequestMessage request = new(method: HttpMethod.Get, uri );
        HttpResponseMessage response = await client.SendAsync(request);


        if (response.IsSuccessStatusCode)
        {
            dynamic result = response.Content.ReadAsStringAsync().Result;
            var jsonObject = JObject.Parse(result);
            Movie moviesList = (jsonObject["results"]).toArray()[0];
            //string[]? titles = moviesList.Select(m => m.title).ToArray();
            Console.WriteLine( moviesList);
            //var movies = JsonConvert.DeserializeObject<Movie>(moviesList);
            ////return View(result);
            //IEnumerable<Movie>? model = await response.Content.ReadFromJsonAsync<IEnumerable<Movie>>().Result;
            //return View(model);
            return View();
        }
        else
        {
            return NotFound();
        }

        
        //return View(model);
            
    }
}

Finally My Movies View:

@using CSApp
@model Movie[]
@{
    ViewData["Title"] = "Movies from Json Requests";
    Movie[]? movies = ViewData["Movies"] as Movie[];
}
<div >
    <h1 >@ViewData["Title"]</h1>
    <p>Other List of movies:</p>
    <table >
        <thead >
        <tr><th>Movie Name</th></tr>
        </thead>
        <tbody>
          @if (Model is not null)
            {
                <table >
                @foreach (Movie m in Model)
                    <tr>
                        <td>@m.title has a avg rating of @m.vote_average</td>

                    </tr>
                </table>
            }
            else
            {
                 <p>No movies found.</p>
            }
        </tbody>
    </table>
</div>

The moviesdb JSON Response looks like this:

{
"page": 1,
"results": [
{
"adult": false,
"backdrop_path": "/wcKFYIiVDvRURrzglV9kGu7fpfY.jpg",
"genre_ids": [
14,
28,
12
],
"id": 453395,
"original_language": "en",
"original_title": "Doctor Strange in the Multiverse of Madness",
"overview": "Doctor Strange, with the help of mystical allies both old and new, traverses the mind-bending and dangerous alternate realities of the Multiverse to confront a mysterious new adversary.",
"popularity": 12833.993,
"poster_path": "/9Gtg2DzBhmYamXBS1hKAhiwbBKS.jpg",
"release_date": "2022-05-04",
"title": "Doctor Strange in the Multiverse of Madness",
"video": false,
"vote_average": 7.5,
"vote_count": 3596
},
{
"adult": false,
"backdrop_path": "/zGLHX92Gk96O1DJvLil7ObJTbaL.jpg",
"genre_ids": [
14,
12,
28
],
"id": 338953,
"original_language": "en",
"original_title": "Fantastic Beasts: The Secrets of Dumbledore",
"overview": "Professor Albus Dumbledore knows the powerful, dark wizard Gellert Grindelwald is moving to seize control of the wizarding world. Unable to stop him alone, he entrusts magizoologist Newt Scamander to lead an intrepid team of wizards and witches. They soon encounter an array of old and new beasts as they clash with Grindelwald's growing legion of followers.",
"popularity": 3338.797,
"poster_path": "/jrgifaYeUtTnaH7NF5Drkgjg2MB.jpg",
"release_date": "2022-04-06",
"title": "Fantastic Beasts: The Secrets of Dumbledore",
"video": false,
"vote_average": 6.8,
"vote_count": 2067
},...

when Trying to convert the response into JsonConvert<IList<Movie>>()... or Movie[], I get a message wrong Properties when trying to parse or so... how can I select the results array from the json, and then parse that as a List of movies to pass to the view????

CodePudding user response:

you have to fix your code

var jsonObject = JObject.Parse(result);
List<Movie> moviesList = jsonObject["results"].ToObject<List<Movie>>();

//if you want the first movie

Movie firstMovie=moviesList[0];

CodePudding user response:

For completeness sake, I also show other ways to return the View(Model): Answer from Serge was correct:

HttpRequestMessage request = new(method: HttpMethod.Get, uri);
HttpResponseMessage response = await client.SendAsync(request);

   if (response.IsSuccessStatusCode)
   {
        dynamic result = response.Content.ReadAsStringAsync().Result;
        var jsonObject = JObject.Parse(result);
        var movie = jsonObject["results"];
        JArray? jArray = JArray.FromObject(movie);
        List<Movie>? movies = jArray?.ToObject<List<Movie>>();

        //or simply:
        List<Movie> moviesList = jsonObject["results"].ToObject<List<Movie>>();

        return View(moviesList);
    }

Another (maybe better) way, is to just create an Interface for your response, that matches your response object's structure:

public class MovieIndexViewModel
    {
        public int? page { get; set; }
        public int? total_pages { get; set; }
        public int? total_results { get; set; }
        public IEnumerable<Movie>? results { get; set; }

    }

then, you can get access to the IEnumerable property, and it also correctly converts the response array of Movie objects (from the Http request) into a List of movies:

if (response.IsSuccessStatusCode)
        {
            MovieIndexViewModel? model = await response.Content.ReadFromJsonAsync<MovieIndexViewModel>();
            IEnumerable<Movie> movies = model?.results;
            Console.WriteLine(movies.Count());

            return View(movies);
      }
  • Related