C
C#•7mo ago
MONO

How to Optimize my API calls?

Trying to get better at some C# with WPFUI, and started a project, is kinda of an imdb application. Showing TV shows, movies, info on both and actors etc. Im using an API to get all the latest movies from one place, and get the ID's from that JSON list. Putting them into an List. And then load all the movie info from another API(TMDB), using the IDs from the first. Its working just fine, but when loading, it takes like 5-10sec before anything is being shown. And when scrolling, its starting to load the new posters, so that takes another 3-5 sec before loading. If i then scroll back up, its loading the first rows again, taking another 3-5 sec. It seems kinda weird and im not sure how to get the scrolling fixed, and how to optimize the API calls, so it does not take 5-10 sec for the info to load. Can this be done in a better way then what i have done? I have created a Gist how give a better view of the code: https://gist.github.com/PatrickRorth/4b634a10eb4a47bd7621d159cfa73d0e I have also added a small recording, showing how it reloads images again after scrolling. Any help would be appriciated.
Gist
Optimize API
Optimize API. GitHub Gist: instantly share code, notes, and snippets.
9 Replies
Becquerel
Becquerel•7mo ago
one thing that stands out to me is this section:
foreach (var movie in VIDSRCmoviesResult)
{
var TMDBmovieInfo = await _tmdbApiClient.GetMovieInfo(movie.tmdb_id);

movie.Title = Regex.Replace(movie.Title, @"\d{4}$", match => $"({match.Value})");

TMDBmovieInfo.poster_path = PosterURL + TMDBmovieInfo.poster_path;
TMDBmovieInfo.title = movie.Title;
TMDBmovieInfo.tmdb_id = movie.tmdb_id;

TMDBmovieCollectionList.Add(TMDBmovieInfo);
}
foreach (var movie in VIDSRCmoviesResult)
{
var TMDBmovieInfo = await _tmdbApiClient.GetMovieInfo(movie.tmdb_id);

movie.Title = Regex.Replace(movie.Title, @"\d{4}$", match => $"({match.Value})");

TMDBmovieInfo.poster_path = PosterURL + TMDBmovieInfo.poster_path;
TMDBmovieInfo.title = movie.Title;
TMDBmovieInfo.tmdb_id = movie.tmdb_id;

TMDBmovieCollectionList.Add(TMDBmovieInfo);
}
specifically the await inside a foreach loop if we assume each call to GetMovieInfo takes one second, and you have ten movies to go through, you're locked-in to at least ten seconds of downtime instead you should consider using await Task.WhenAll(...) to await all of that i/o at once it would look something like this:
var tasks = movies.Select(movie => _tmdbApiClient.GetMovieInfo(movie.tmdb_id));
var results = await Task.WhenAll(tasks);

foreach (var movie in results)
{
// ...
}
var tasks = movies.Select(movie => _tmdbApiClient.GetMovieInfo(movie.tmdb_id));
var results = await Task.WhenAll(tasks);

foreach (var movie in results)
{
// ...
}
as for the scrolling issue, you probably just want to cache your results rather than writing directly to your viemodel property (TMDBmovies)
Becquerel
Becquerel•7mo ago
you may find this snippet from david fowler useful: https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md
public class PersonController : Controller
{
private AppDbContext _db;

private static ConcurrentDictionary<int, AsyncLazy<Person>> _cache = new ConcurrentDictionary<int, AsyncLazy<Person>>();

public PersonController(AppDbContext db)
{
_db = db;
}

public async Task<IActionResult> Get(int id)
{
var person = await _cache.GetOrAdd(id, (key) => new AsyncLazy<Person>(() => _db.People.FindAsync(key))).Value;
return Ok(person);
}

private class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<Task<T>> valueFactory) : base(valueFactory)
{
}
}
}
public class PersonController : Controller
{
private AppDbContext _db;

private static ConcurrentDictionary<int, AsyncLazy<Person>> _cache = new ConcurrentDictionary<int, AsyncLazy<Person>>();

public PersonController(AppDbContext db)
{
_db = db;
}

public async Task<IActionResult> Get(int id)
{
var person = await _cache.GetOrAdd(id, (key) => new AsyncLazy<Person>(() => _db.People.FindAsync(key))).Value;
return Ok(person);
}

private class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<Task<T>> valueFactory) : base(valueFactory)
{
}
}
}
GitHub
AspNetCoreDiagnosticScenarios/AsyncGuidance.md at master · davidfow...
This repository has examples of broken patterns in ASP.NET Core applications - davidfowl/AspNetCoreDiagnosticScenarios
MONO
MONOOP•7mo ago
oh nice!
Becquerel
Becquerel•7mo ago
the key parts being the AsyncLazy class he creates and uses
MONO
MONOOP•7mo ago
I load in around 50 movies from the VIDSRCAPI, is that to much? i would like a full overview, and not just load 5 at at time
Becquerel
Becquerel•7mo ago
each API has their own rate limits you need to follow but speaking informally, 50 requests is not a lot at all so i think you would be fine to just load them all at once
MONO
MONOOP•7mo ago
nice niec! Ill def. try that! Thank you so much!
Becquerel
Becquerel•7mo ago
no prob 🙂 have fun
MONO
MONOOP•7mo ago
thanks, i sure will! 😄
Want results from more Discord servers?
Add your server