c# JsonConvert.DeserializeObject<List<Movie>>(content) 在返回 JSON 嵌套的情况下不起作用



我是xamarin表单的新手。我使用第三方api根据标题的搜索文本检索电影列表。我使用的第三方电影api低于

[movie api][1]
http://www.omdbapi.com/?apikey==*******&s=man

这将返回如下所示的JSON数据

{"Search":[{"Title":"Iron Man","Year":"2008","imdbID":"tt0371746","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMTczNTI2ODUwOF5BMl5BanBnXkFtZTcwMTU0NTIzMw@@._V1_SX300.jpg"},{"Title":"Iron Man 3","Year":"2013","imdbID":"tt1300854","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMjE5MzcyNjk1M15BMl5BanBnXkFtZTcwMjQ4MjcxOQ@@._V1_SX300.jpg"},{"Title":"Iron Man 2","Year":"2010","imdbID":"tt1228705","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMTM0MDgwNjMyMl5BMl5BanBnXkFtZTcwNTg3NzAzMw@@._V1_SX300.jpg"},{"Title":"Man of Steel","Year":"2013","imdbID":"tt0770828","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMTk5ODk1NDkxMF5BMl5BanBnXkFtZTcwNTA5OTY0OQ@@._V1_SX300.jpg"},{"Title":"Spider-Man","Year":"2002","imdbID":"tt0145487","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BZDEyN2NhMjgtMjdhNi00MmNlLWE5YTgtZGE4MzNjMTRlMGEwXkEyXkFqcGdeQXVyNDUyOTg3Njg@._V1_SX300.jpg"},{"Title":"Ant-Man","Year":"2015","imdbID":"tt0478970","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMjM2NTQ5Mzc2M15BMl5BanBnXkFtZTgwNTcxMDI2NTE@._V1_SX300.jpg"},{"Title":"The Amazing Spider-Man","Year":"2012","imdbID":"tt0948470","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMjMyOTM4MDMxNV5BMl5BanBnXkFtZTcwNjIyNzExOA@@._V1_SX300.jpg"},{"Title":"Spider-Man 2","Year":"2004","imdbID":"tt0316654","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMzY2ODk4NmUtOTVmNi00ZTdkLTlmOWYtMmE2OWVhNTU2OTVkXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX300.jpg"},{"Title":"Spider-Man: Homecoming","Year":"2017","imdbID":"tt2250912","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BNTk4ODQ1MzgzNl5BMl5BanBnXkFtZTgwMTMyMzM4MTI@._V1_SX300.jpg"},{"Title":"Spider-Man 3","Year":"2007","imdbID":"tt0413300","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BYTk3MDljOWQtNGI2My00OTEzLTlhYjQtOTQ4ODM2MzUwY2IwXkEyXkFqcGdeQXVyNTIzOTk5ODM@._V1_SX300.jpg"}],"totalResults":"10750","Response":"True"}

JSON数据中有三个部分——";搜索"totalResult";以及";响应";

我需要访问";搜索";部分,并将其取消为我的POCO类电影。我该怎么做?

我的电影POCO课程低于

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace NetflixRouletteApp.Models
{
public class Movie
{

[JsonProperty("Title")]
public string Title { get; set; }
[JsonProperty("Year")]
public int Year { get; set; }
[JsonProperty("Released")]
public DateTime Released { get; set; }

[JsonProperty("Rated")]
public string Rated { get; set; }
[JsonProperty("Runtime")]
public string Runtime { get; set; }
[JsonProperty("Genre")]
public string Genre { get; set; }
[JsonProperty("Director")]
public string Director { get; set; }
[JsonProperty("Writer")]
public string Writer { get; set; }
[JsonProperty("Actors")]
public string Actors { get; set; }
[JsonProperty("Plot")]
public string Plot { get; set; }
[JsonProperty("Language")]
public string Language { get; set; }
[JsonProperty("Country")]
public string Country { get; set; }
[JsonProperty("Awards")]
public string Awards { get; set; }
[JsonProperty("Poster")]
public string Poster { get; set; }
[JsonProperty("Type")]
public string mtype { get; set; }
}
}

MovieService.cs是

using NetflixRouletteApp.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using RestSharp;
using RestSharp.Authenticators;
using System.Threading;
using System.Net.Http.Headers;
using Newtonsoft.Json.Linq;
namespace NetflixRouletteApp.Services
{
public class MovieService
{
public static readonly int MinSearchLength = 3;
private const string Url = "http://www.omdbapi.com/?apikey=d09e0406";
private HttpClient _client = new HttpClient();
public static Exception CreateExceptionFromResponseErrors(HttpResponseMessage response)
{
var httpErrorObject = response.Content.ReadAsStringAsync().Result;
// Create an anonymous object to use as the template for deserialization:
var anonymousErrorObject =
new { message = "", ModelState = new Dictionary<string, string[]>() };
// Deserialize:
var deserializedErrorObject =
JsonConvert.DeserializeAnonymousType(httpErrorObject, anonymousErrorObject);
// Now wrap into an exception which best fullfills the needs of your application:
var ex = new Exception();
// Sometimes, there may be Model Errors:
if (deserializedErrorObject.ModelState != null)
{
var errors =
deserializedErrorObject.ModelState
.Select(kvp => string.Join(". ", kvp.Value));
for (int i = 0; i < errors.Count(); i++)
{
// Wrap the errors up into the base Exception.Data Dictionary:
ex.Data.Add(i, errors.ElementAt(i));
}
}
// Othertimes, there may not be Model Errors:
else
{
var error =
JsonConvert.DeserializeObject<Dictionary<string, string>>(httpErrorObject);
foreach (var kvp in error)
{
// Wrap the errors up into the base Exception.Data Dictionary:
ex.Data.Add(kvp.Key, kvp.Value);
}
}
return ex;
}
public async Task<IEnumerable<Movie>> FindMoviesByActor(string title)
{

_client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await _client.GetAsync($"{Url}&s={title}");
response.EnsureSuccessStatusCode();
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return Enumerable.Empty<Movie>();

var content =  response.Content.ReadAsStringAsync().Result;

List<Movie> movies = JsonConvert.DeserializeObject<List<Movie>>(content);
movies.ForEach(Console.WriteLine);
return movies;
}
catch {
// Unwrap the response and throw as an Api Exception:
var ex = CreateExceptionFromResponseErrors(response);
throw ex;
}
}

public async Task<Movie> GetMovie(string title)
{
var response = await _client.GetAsync($"{Url}&t={title}");
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
var content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Movie>(content);
}
}
}

MoviePage.Xaml

<? xml version = "1.0" encoding = "utf-8" ?>
< ContentPage xmlns = "http://xamarin.com/schemas/2014/forms"
xmlns: x = "http://schemas.microsoft.com/winfx/2009/xaml"
x: Class = "NetflixRouletteApp.Views.MoviesPage" >
< StackLayout >

< SearchBar x: Name = "searchBar"
Placeholder = "Enter value..."
SearchCommand = "{Binding SearchButtonPressed}"
SearchCommandParameter = "{Binding Source={x:Reference searchBar}, Path=Text}" />
< !--< ActivityIndicator IsRunning = "{Binding IsSearching}" /> -->
< Frame x: Name = "notFound" Padding = "20" HasShadow = "False" IsVisible = "False" >

< Label Text = "No movies found matching your search." TextColor = "Gray" ></ Label >

</ Frame >

< ListView x: Name = "moviesListView" ItemSelected = "OnMovieSelected" >

< ListView.ItemTemplate >

< DataTemplate >

< ImageCell ImageSource = "{Binding Poster}"
Text = "{Binding Title}"
Detail = "{Binding Year}" ></ ImageCell >
</ DataTemplate >
</ ListView.ItemTemplate >
</ ListView >
</ StackLayout >
</ ContentPage >

MoviePage.xaml.cs

using NetflixRouletteApp.Models;
using NetflixRouletteApp.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace NetflixRouletteApp.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MoviesPage : ContentPage
{
private MovieService _movieService = new MovieService();
// Note that IsSearching is a bindable property. This is required for 
// binding ActivityIndicator's IsRunning property. If we do not define 
// IsSearching as a bindable property, its initial value (false) will 
// be used to set ActivityIndicator.IsRunning. Later when we change
// the value of IsSearching, ActivityIndicator will be unaware of this. 
// So, we need to implement it as a bindable property. 
//private BindableProperty IsSearchingProperty = BindableProperty.Create("IsSearching",
//    typeof(bool), typeof(MoviesPage), false);
public ICommand SearchButtonPressed { private set; get; }


public MoviesPage()
{
BindingContext = this;
SearchButtonPressed = new Command<string>(HandleSearchPressed);
InitializeComponent();
}
async void HandleSearchPressed(string searchText)
{

if (searchText == null)
return;

await FindMovies(title: searchText);
}

async Task FindMovies(string title)
{

try
{
var movies = await _movieService.FindMoviesByActor(title);
moviesListView.ItemsSource = movies;
moviesListView.IsVisible = movies.Any();
notFound.IsVisible = !moviesListView.IsVisible;
}
catch (Exception)
{
await DisplayAlert("Error", "Could not retrieve the list of movies.", "OK");
}

}
async void OnTextChanged(object sender, TextChangedEventArgs e)
{

if (e.NewTextValue == null)
return;

await FindMovies(title: e.NewTextValue);
}
async void OnMovieSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
return;
var movie = e.SelectedItem as Movie;
moviesListView.SelectedItem = null;
await Navigation.PushAsync(new MovieDetailsPage(movie));
}
}
}

转到json2csharp.com并粘贴您的json,它将生成这个C#类

public class Movie    {
public string Title { get; set; } 
public string Year { get; set; } 
public string imdbID { get; set; } 
public string Type { get; set; } 
public string Poster { get; set; } 
}
public class Root    {
public List<Movie> Search { get; set; } 
public string totalResults { get; set; } 
public string Response { get; set; } 
}

然后在服务层中反序列化响应

Root root = JsonConvert.DeserializeObject<Root>(content);
List<Movie> Movies = root.Search;

最新更新