Implementing TheMovieDB (TMDB) API in ASP.NET MVC – [with full codes]

Implementing TheMovieDB (TMDB) API in ASP.NET MVC – [with full codes]

Introduction to TheMovieDB API

The Movie Database (TMDb) is a community built movie and TV database. Every piece of data has been added dating back to 2008. TMDb’s strong international focus and breadth of data is largely unmatched and available through the mean of TheMovieDb API. You can use this API to create different sort of features like searching movie, actors, TV series, companies, reviews and much more.

In this tutorial I will implement TMDB API, so users can search any actor by name and get their complete details. I will implement this in ASP.NET MVC application.

PDF is a widely used medium of displaying information like sales report, bills, database records, etc. Creating a pdf file is never been so easy, all the credit goes to iTextSharp. You can learn how to Create a PDF file in ASP.NET by visiting this tutorial.

Generate you API Key

First you need to create your account in the TMDB Website then go to the Settings & API to generate your API key.

More information is given here.

What the Application will Look

I will create 2 Views – in the first View, the users can search actors by their names.

TheMovieDB actor result

In the second View the information of an selected actor is shown.

TheMovieDB tom cruise result

Note – The user will be redirected to the second View when the image of an actor shown on the first View is clicked.

Very Important – I have also written a full tutorial on Implementing the TMDB API using just jQuery. You should also read this tutorial.

Create TheMovieDb Model

Let’s move to the implementation part of TheMovieDb API.

Add a new class to the Models folder and name it TheMovieDb.cs, next add the following properties to it.

public class TheMovieDb
{
    [Required]
    public string searchText { get; set; }
    public bool adult { get; set; }
    public string also_known_as { get; set; }
    public string biography { get; set; }
    public string birthday { get; set; }
    public string deathday { get; set; }
    public int gender { get; set; }
    public string homepage { get; set; }
    public int id { get; set; }
    public string imdb_id { get; set; }
    public string name { get; set; }
    public string place_of_birth { get; set; }
    public double popularity { get; set; }
    public string profile_path { get; set; }
}

Create Some Helper Classes

I will need some Helper classes to serialize the JSON and for creating the paging links.

So create these classes inside a new Class folder. These classes are:

public class KnownFor
{
    public string poster_path { get; set; }
    public bool adult { get; set; }
    public string overview { get; set; }
    public string release_date { get; set; }
    public string original_title { get; set; }
    public List<object> genre_ids { get; set; }
    public int id { get; set; }
    public string media_type { get; set; }
    public string original_language { get; set; }
    public string title { get; set; }
    public string backdrop_path { get; set; }
    public double popularity { get; set; }
    public int vote_count { get; set; }
    public bool video { get; set; }
    public double vote_average { get; set; }
    public string first_air_date { get; set; }
    public List<string> origin_country { get; set; }
    public string name { get; set; }
    public string original_name { get; set; }
}

public class Result
{
    public string profile_path { get; set; }
    public bool adult { get; set; }
    public int id { get; set; }
    public List<KnownFor> known_for { get; set; }
    public string name { get; set; }
    public double popularity { get; set; }
}

public class ResponseSearchPeople
{
    public int page { get; set; }
    public List<Result> results { get; set; }
    public int total_results { get; set; }
    public int total_pages { get; set; }
}

public class ResponsePerson
{
    public bool adult { get; set; }
    public List<string> also_known_as { get; set; }
    public string biography { get; set; }
    public string birthday { get; set; }
    public string deathday { get; set; }
    public int gender { get; set; }
    public string homepage { get; set; }
    public int id { get; set; }
    public string imdb_id { get; set; }
    public string name { get; set; }
    public string place_of_birth { get; set; }
    public double popularity { get; set; }
    public string profile_path { get; set; }
}
public class PagingInfo
{
    public int TotalItems { get; set; }
    public int ItemsPerPage { get; set; }
    public int CurrentPage { get; set; }
    public int TotalPages
    {
        get
        {
            return (int)Math.Ceiling((decimal)TotalItems /
                ItemsPerPage);
        }
    }
}

public static class PagingHelper
{
    public static MvcHtmlString PageLinks(this HtmlHelper html, PagingInfo pagingInfo, Func<int, string> pageUrl)
    {
        StringBuilder result = new StringBuilder();
        string anchorInnerHtml = "";
        for (int i = 1; i <= pagingInfo.TotalPages; i++)
        {
            TagBuilder tag = new TagBuilder("a");
            anchorInnerHtml = AnchorInnerHtml(i, pagingInfo);

            if (anchorInnerHtml == "..")
                tag.MergeAttribute("href", "#");
            else
                tag.MergeAttribute("href", pageUrl(i));
            tag.InnerHtml = anchorInnerHtml;
            if (i == pagingInfo.CurrentPage)
            {
                tag.AddCssClass("active");
            }
            tag.AddCssClass("paging");
            if (anchorInnerHtml != "")
                result.Append(tag.ToString());
        }
            return MvcHtmlString.Create(result.ToString());
    }
    
    public static string AnchorInnerHtml(int i, PagingInfo pagingInfo)
    {
        string anchorInnerHtml = "";
        if (pagingInfo.TotalPages <= 10)
            anchorInnerHtml = i.ToString();
        else
        {
            if (pagingInfo.CurrentPage <= 5)
            {
                if ((i <= 8) || (i == pagingInfo.TotalPages))
                    anchorInnerHtml = i.ToString();
                else if (i == pagingInfo.TotalPages - 1)
                    anchorInnerHtml = "..";
            }
            else if ((pagingInfo.CurrentPage > 5) && (pagingInfo.TotalPages - pagingInfo.CurrentPage >= 5))
            {
                if ((i == 1) || (i == pagingInfo.TotalPages) || ((pagingInfo.CurrentPage - i >= -3) && (pagingInfo.CurrentPage - i <= 3)))
                    anchorInnerHtml = i.ToString();
                else if ((i == pagingInfo.CurrentPage - 4) || (i == pagingInfo.CurrentPage + 4))
                    anchorInnerHtml = "..";
            }
            else if (pagingInfo.TotalPages - pagingInfo.CurrentPage < 5)
            {
                if ((i == 1) || (pagingInfo.TotalPages - i <= 7))
                    anchorInnerHtml = i.ToString();
                else if (pagingInfo.TotalPages - i == 8)
                    anchorInnerHtml = "..";
            }
        }
        return anchorInnerHtml;
    }
}

To serialize JSON, you have to create classes based on JSON data returned by the TheMovieDb API. This task is a good time consuming work so I tell you to use json2csharp to make these classes instantly based on your JSON format. It will save 1 hour of your time.

Create TMDB Controller

Create a new Controller and name it TmdbApi, and add the following Namespaces to it:

using System.Net;
using System.IO;
using Newtonsoft.Json;
using demo.MVC.Class;
using System.Text;

Now add the below code to it:

// GET
public ActionResult Index(string peopleName, int? page)
{
    if (page != null)
        CallAPI(peopleName, Convert.ToInt32(page));

    Models.TheMovieDb theMovieDb = new Models.TheMovieDb();
    theMovieDb.searchText = peopleName;
    return View(theMovieDb);
}

[HttpPost]
public ActionResult Index(Models.TheMovieDb theMovieDb, string searchText)
{
    if (ModelState.IsValid)
    {
        CallAPI(searchText, 0);
    }
    return View(theMovieDb);
}

public void CallAPI(string searchText, int page)
{
    int pageNo = Convert.ToInt32(page) == 0 ? 1 : Convert.ToInt32(page);

    /*Calling API https://developers.themoviedb.org/3/search/search-people */
    string apiKey = "3356865d41894a2fa9bfa84b2b5f59bb";
    HttpWebRequest apiRequest = WebRequest.Create("https://api.themoviedb.org/3/search/person?api_key=" + apiKey + "&language=en-US&query=" + searchText + "&page=" + pageNo + "&include_adult=false") as HttpWebRequest;

    string apiResponse = "";
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3
                    | SecurityProtocolType.Tls
                    | SecurityProtocolType.Tls11
                    | SecurityProtocolType.Tls12;
    using (HttpWebResponse response = apiRequest.GetResponse() as HttpWebResponse)
    {
        StreamReader reader = new StreamReader(response.GetResponseStream());
        apiResponse = reader.ReadToEnd();
    }
    /*End*/

    /*http://json2csharp.com*/
    ResponseSearchPeople rootObject = JsonConvert.DeserializeObject<ResponseSearchPeople>(apiResponse);

    StringBuilder sb = new StringBuilder();
    sb.Append("<div class=\"resultDiv\"><p>Names</p>");
    foreach (Result result in rootObject.results)
    {
        string image = result.profile_path == null ? Url.Content("~/Content/Image/no-image.png") : "https://image.tmdb.org/t/p/w500/" + result.profile_path;
        string link = Url.Action("GetPerson", "TmdbApi", new { id = result.id });
        
        sb.Append("<div class=\"result\" resourceId=\"" + result.id + "\">" + "<a href=\"" + link + "\"><img src=\"" + image + "\" />" + "<p>" + result.name + "</a></p></div>");
    }
    
    ViewBag.Result = sb.ToString();

    int pageSize = 20;
    PagingInfo pagingInfo = new PagingInfo();
    pagingInfo.CurrentPage = pageNo;
    pagingInfo.TotalItems = rootObject.total_results;
    pagingInfo.ItemsPerPage = pageSize;
    ViewBag.Paging = pagingInfo;
}

public ActionResult GetPerson(int id)
{
    /*Calling API https://developers.themoviedb.org/3/people */
    string apiKey = "3356865d41894a2fa9bfa84b2b5f59bb";
    HttpWebRequest apiRequest = WebRequest.Create("https://api.themoviedb.org/3/person/" + id + "?api_key=" + apiKey + "&language=en-US") as HttpWebRequest;

    string apiResponse = "";
    using (HttpWebResponse response = apiRequest.GetResponse() as HttpWebResponse)
    {
        StreamReader reader = new StreamReader(response.GetResponseStream());
        apiResponse = reader.ReadToEnd();
    }
    /*End*/

    /*http://json2csharp.com*/
    ResponsePerson rootObject = JsonConvert.DeserializeObject<ResponsePerson>(apiResponse);
    TheMovieDb theMovieDb = new TheMovieDb();
    theMovieDb.name = rootObject.name;
    theMovieDb.biography = rootObject.biography;
    theMovieDb.birthday = rootObject.birthday;
    theMovieDb.place_of_birth = rootObject.place_of_birth;
    theMovieDb.profile_path = rootObject.profile_path == null ? Url.Content("~/Content/Image/no-image.png") : "https://image.tmdb.org/t/p/w500/" + rootObject.profile_path;
    theMovieDb.also_known_as = string.Join(", ", rootObject.also_known_as);

    return View(theMovieDb);
}

Explanation
Let me explain you the above code of the Controller.

HTTP GET Index Action Method: It has 2 parameters – string peopleName, int? page. I will be using this method for doing the actor search (by their names) through this API.

The parameter called peopleName will contains the value of the text box (that contains actor’s name), while the parameter called page will contain the current page number as given in the URL.

Consider – If the URL is ‘http://localhost:64253/TmdbApi/nicole/1’ then ‘peopleName’ will receive value of ‘nicole’ while ‘page’ will receive the value of ‘1’.

Similarly for the URL like ‘http://localhost:64253/TmdbApi/tom%20cruise/3’ the ‘peopleName’ will receive ‘tom cruise’ while ‘page’ will receive ‘3’.

This method calls CallAPI() which will make the actual API call. I have passed the ‘name’ of the actor and the ‘page number’ to this method.

HTTP POST Index Action Method: It makes the call to the CallAPI() method. I pass the actor name and ‘0’ for the page number, telling it to get me the 1st page for the search result.

CallAPI(): The most important is the CallAPI() method where I am implementing TheMovieDb API. Here I append API key, actor’s name and page number to the API URL which is – https://api.themoviedb.org/3/search/person.

I get the result in JSON format which is serialized into the ResponseSearchPeople class. For doing this Serialization I use the JsonConvert class from namespace Newtonsoft.Json .

Then I create an HTML by extracting values from the ResponseSearchPeople class and set it to a Viewbag object. I will show this HTML in my Index view.

I am also using the PagingInfo class to create the paging links for the View.

GetPerson() Method: This method calls the TheMovieDb API once more, and this time it passes the actors id to it. The API sends back the JSON containing the complete information of the given actors. I will show this information inside the GetPerson View.

Create Index View

Create an Index View and add following code to it:

@model demo.MVC.Models.TheMovieDb
@using demo.MVC.Class;
<style>
    body {
        background-color: #000;
    }

    #apiDiv {
        padding-left: 20px;
    }

        #apiDiv input, #apiDiv button {
            font-size: 25px;
            color: #000;
        }

        #apiDiv h4 {
            margin: 10px 0;
            color: #00e8ff;
            font-size: 20px;
        }

        #apiDiv .textAlignCenter {
            text-align: center;
        }

            #apiDiv .textAlignCenter img {
                display: none;
                width: 100px;
            }

        #apiDiv #message {
            padding-top: 10px;
        }

            #apiDiv #message .resultDiv {
                background: #FFF;
                display: inline-block;
            }

                #apiDiv #message .resultDiv > p {
                    color: #000;
                    display: inline-block;
                    width: 95%;
                    padding: 10px;
                    border-bottom: double 2px #CCC;
                }

                #apiDiv #message .resultDiv .result {
                    width: 23%;
                    height: 240px;
                    padding: 6px;
                    float: left;
                    text-align: center;
                    cursor: pointer;
                }

                    #apiDiv #message .resultDiv .result img {
                        width: 75%;
                    }

                    #apiDiv #message .resultDiv .result p {
                        margin: 0;
                    }

                        #apiDiv #message .resultDiv .result p a {
                            color: #808080;
                            text-decoration: none;
                            font-size: 20px;
                            height: 100px;
                        }

                            #apiDiv #message .resultDiv .result p a:hover {
                                text-decoration: underline;
                            }

        #apiDiv form span {
            color: red;
            font-size: 20px;
        }

    .pagingDiv {
        background: #f2f2f2;
    }

        .pagingDiv > a {
            display: inline-block;
            padding: 0px 9px;
            margin-right: 4px;
            border-radius: 3px;
            border: solid 1px #c0c0c0;
            background: #e9e9e9;
            box-shadow: inset 0px 1px 0px rgba(255,255,255, .8), 0px 1px 3px rgba(0,0,0, .1);
            font-size: .875em;
            font-weight: bold;
            text-decoration: none;
            color: #717171;
            text-shadow: 0px 1px 0px rgba(255,255,255, 1);
        }

            .pagingDiv > a:hover {
                background: #fefefe;
                background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#FEFEFE), to(#f0f0f0));
                background: -moz-linear-gradient(0% 0% 270deg,#FEFEFE, #f0f0f0);
            }

            .pagingDiv > a.active {
                border: none;
                background: #616161;
                box-shadow: inset 0px 0px 8px rgba(0,0,0, .5), 0px 1px 0px rgba(255,255,255, .8);
                color: #f0f0f0;
                text-shadow: 0px 0px 3px rgba(0,0,0, .5);
            }
</style>

<div id="apiDiv">
    <h4>Enter the Search Text and Press Submit Button</h4>
    @using (Html.BeginForm())
    {
        @Html.EditorFor(model => model.searchText)
        <button id="submit">Submit</button>
        @Html.ValidationMessageFor(model => model.searchText)
    }
    <div id="message">
        @(new HtmlString(ViewBag.Result))
    </div>
    <div class="pagingDiv">
        @{
            PagingInfo pagingInfo = (PagingInfo)ViewBag.Paging;
            if (pagingInfo != null)
            {
                @Html.PageLinks((PagingInfo)ViewBag.Paging, x => Url.Action("Index", "TmdbApi", new { peopleName = Model.searchText, page = x }))
            }
        }
    </div>
</div>

Explanation

I am using some CSS to make the View look good design wise. The View has a search text box and a button from where you can do the API search for the actors. The result is shown inside the message div.

The pagination links are shown in the pagingDiv div.

Since I will be using the classes kept in the Class folder therefore I have imported them in the View by – @using demo.MVC.Class;.

Create GetPerson View

Create a new View and give it the name as GetPerson. Add the following codes to it:

@model demo.MVC.Models.TheMovieDb
<style>
    body {
        background-color: #000;
    }

    #apiDiv {
        padding-left: 20px;
        display: inline-block;
        width: 95%;
        text-align: justify;
    }

        #apiDiv h4 {
            margin: 10px 0;
        }

        #apiDiv .biography img {
            float: left;
            padding-right: 10px;
        }

        #apiDiv .return {
            text-align: center;
        }

            #apiDiv .return a {
                color: #00e8ff;
                font-size: 20px;
                text-decoration: underline;
            }
</style>

<div id="apiDiv">
    <div class="return"><a href="@Url.Action("Index", "TmdbApi")">Return</a></div>
    <h4>@Model.name</h4>
    <p class="biography"><img src="@Model.profile_path" />@Model.biography</p>
    <p>Birthday: @Model.birthday</p>
    <p>Place of Birth: @Model.place_of_birth</p>
    <p>Also Known as: @Model.also_known_as</p>
</div>

Explanation
This view will show an actor’s complete information by calling TheMovieDb API.

Add Routing Rules

Add the below rules in your RouteConfig.cs file:

routes.MapRoute(
    name: "TmdbApi",
    url: "TmdbApi/{id}/",
    defaults: new { controller = "TmdbApi", action = "GetPerson", id = "" },
    constraints: new { id = @"^[0-9]+$" }
);

routes.MapRoute(
    name: "TmdbApiPaging",
    url: "TmdbApi/{peopleName}/{page}",
    defaults: new { controller = "TmdbApi", action = "Index", peopleName = "", page = "" },
    constraints: new { peopleName = @"^[a-zA-Z]+$", page = @"^[0-9]+$" }
);

Explanation
The work of these rules is to create a URL structure that is given below:

For searching through actors – http://localhost:64253/TmdbApi/actorName/page.

For fetching a particular actor’s information – http://localhost:64253/TmdbApi/982722.

DEMO DOWNLOAD

Would you like to dig deep into the world of database programming with C#? Then you can check this series of tutorials on Entity Framework Core that help you to learn database programming within a few hours time.

Share this article -

yogihosting

ABOUT THE AUTHOR

This article has been written by the Technical Staff of YogiHosting. Check out other articles on "ASP.NET Core, jQuery, EF Core, SEO, jQuery, HTML" and more.