Marvel API C#

Get Marvel Characters via C#

“Genius, Billionaire, Playboy, Philanthropist” ~ Tony Stark”

Description

This includes a C# Model, Mainpage.xaml.cs class, and a Mainpage.xaml view in a Universal Windows Platform (UWP) application. This code will get a random Marvel Character from the Marvel API (starting at 20 seconds) and display the characters in a random 20 second rotation on a UWP application background. I am currently using this API and method to generate characters on the background of my Raspberry PI3 thermostat using Winodws 10 IOT Core. Full code is available below in the references section.

Known Issues

While the Marvel API is neat, and free, there are several blank character images available in the API. If you want to use this in an application to show a Marvel character image every time, you should filter out the images that are not available. I did some, but not all of the filtering. While all the “return null” statements in the model may seem excessive, I noticed application crashes when any of those were excluded, so that is why I left it as is.

Model

You will need to go over to {:#testid} https://developer.marvel.com/ to get your own API keys to use in this model. To use this model, just input your keys in place of the publickey and privatekey.

The MD5 hash was the hardest part, but thanks to Channel 9, reference below, I was able to get it working.

Note that I have the DateTime modified commented out above due to application errors when having that attribute in the Model. You can delete whatever attributes you do not need if you would like.

You can’t return all the marvel characters at once, so I have included a random offset between 0 and 1400 to randomize the returned results. Yes, I am twice over randomizing the results to allow for character growth and reduction, while still picking a random character overall.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;

namespace GetMarvelCharacter.MarvelAPI
{
    class GetMarvelCharacter
    {
        private const string publickey = "enter key";
        private const string privatekey = "enter key";

        public async static Task<RootObject> GetCharacter(int CharacterID)
        {
            try
            {
                Random random = new Random();
                int offset = random.Next(0, 1400);
                string requesturl = "https://gateway.marvel.com:443/v1/public/characters?offset=" + offset + CreateHash();
                System.Diagnostics.Debug.WriteLine(requesturl);
                var http = new HttpClient();
                var response = await http.GetAsync(requesturl);
                var result = await response.Content.ReadAsStringAsync();
                var serializer = new DataContractJsonSerializer(typeof(RootObject));
                var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
                if (response.IsSuccessStatusCode == true)
                {
                   if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable() == true)
                    {
                        var data = (RootObject)serializer.ReadObject(ms);
                        return data;
                    }
                    else
                   {
                        return null;
                    }
                }
               else
               {
                   return null;
                }
               
            }
            catch 
            {
             return null;
            }
        }

        private static string CreateHash()
        {
            var timestamp = DateTime.Now.Ticks.ToString();
            var toBeHashed = timestamp + privatekey + publickey;
            var hashedmessage = ComputeMD5(toBeHashed);
            var urlsuffix = "&ts=" + timestamp + "&apikey=" + publickey + "&hash=" + hashedmessage;
            return urlsuffix;
        }
        private static string ComputeMD5(string str)
        {
            var alg = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
            IBuffer buff = CryptographicBuffer.ConvertStringToBinary(str, BinaryStringEncoding.Utf8);
            var hashed = alg.HashData(buff);
            var res = CryptographicBuffer.EncodeToHexString(hashed);
            return res;

        }
    }
    [DataContract]
    public class Thumbnail
    {
        [DataMember]
        public string path { get; set; }
        [DataMember]
        public string extension { get; set; }
    }
    [DataContract]
    public class Comics
    {
        [DataMember]
        public int available { get; set; }
        [DataMember]
        public string collectionURI { get; set; }
        [DataMember]
        public List<object> items { get; set; }
        [DataMember]
        public int returned { get; set; }
    }
    [DataContract]
    public class Series
    {
        [DataMember]
        public int available { get; set; }
        [DataMember]
        public string collectionURI { get; set; }
        [DataMember]
        public List<object> items { get; set; }
        [DataMember]
        public int returned { get; set; }
    }
    [DataContract]
    public class Stories
    {
        [DataMember]
        public int available { get; set; }
        [DataMember]
        public string collectionURI { get; set; }
        [DataMember]
        public List<object> items { get; set; }
        [DataMember]
        public int returned { get; set; }
    }
    [DataContract]
    public class Events
    {
        [DataMember]
        public int available { get; set; }
        [DataMember]
        public string collectionURI { get; set; }
        [DataMember]
        public List<object> items { get; set; }
        [DataMember]
        public int returned { get; set; }
    }
    [DataContract]
    public class Url
    {
        [DataMember]
        public string type { get; set; }
        [DataMember]
        public string url { get; set; }
    }
    [DataContract]
    public class Result
    {
        [DataMember]
        public int id { get; set; }
        [DataMember]
        public string name { get; set; }
        [DataMember]
        public string description { get; set; }
        //  [DataMember]
        //  public DateTime modified { get; set; }
        [DataMember]
        public Thumbnail thumbnail { get; set; }
        [DataMember]
        public string resourceURI { get; set; }
        [DataMember]
        public Comics comics { get; set; }
        [DataMember]
        public Series series { get; set; }
        [DataMember]
        public Stories stories { get; set; }
        [DataMember]
        public Events events { get; set; }
        [DataMember]
        public List<Url> urls { get; set; }
    }
    [DataContract]
    public class Data
    {
        [DataMember]
        public int offset { get; set; }
        [DataMember]
        public int limit { get; set; }
        [DataMember]
        public int total { get; set; }
        [DataMember]
        public int count { get; set; }
        [DataMember]
        public List<Result> results { get; set; }
    }
    [DataContract]
    public class RootObject
    {
        [DataMember]
        public int code { get; set; }
        [DataMember]
        public string status { get; set; }
        [DataMember]
        public string copyright { get; set; }
        [DataMember]
        public string attributionText { get; set; }
        [DataMember]
        public string attributionHTML { get; set; }
        [DataMember]
        public string etag { get; set; }
        [DataMember]
        public Data data { get; set; }
    }
}

Mainpage.Xaml.cs Class (UWP Application)

This class includes a 20 second rotation for a background image in a a UWP application. I have included a random index selector to pick a random character from the returned results. If the image is not available, the code does not show the image, but shows a local image of wonderwoman. Note that the local image is found in the applications image directory. You will need to add your own local image and reference your local directory.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Runtime.Serialization;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace GetMarvelCharacter
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            try
            {
                GetMarvelCharacter();
            }
            catch
            {
                LblError.Text = "Can't set marvel character.";
            }
        }
        private void GetMarvelCharacter()
        {

            var backgroundtimer = new DispatcherTimer
            {
                Interval = TimeSpan.FromSeconds(20)
            };
            backgroundtimer.Tick += async (o, e) =>
            {
                //Try to get Iron Man
                MarvelAPI.RootObject mycharacter = await MarvelAPI.GetMarvelCharacter.GetCharacter(1009610);
                //Make sure you recieved good data. Class returns null if something is broken.
                if (mycharacter != null)
                {
                    int resultindex = (mycharacter.data.results.Count) - 1;
                    Random random = new Random();
                    int randomindex = random.Next(0, resultindex);
                    string badimage = "image_not_available";
                    string imageurl = mycharacter.data.results[randomindex].thumbnail.path + "." + mycharacter.data.results[randomindex].thumbnail.extension;
                    //If the image is not available, change background to wonderwoman image. You need to add your own image, I am only providing a blank image.
                    if (imageurl.Contains(badimage))
                    {
                        imgBackground.Source = new BitmapImage(new Uri(this.BaseUri, "Assets/Backgrounds/wonderwoman.png"));
                        LblCharacter.Text = "Wonder Woman :)";
                    }
                    if (!imageurl.Contains(badimage))
                    {
                        imgBackground.Source = new BitmapImage(new Uri(imageurl, UriKind.Absolute));
                        LblCharacter.Text = mycharacter.data.results[randomindex].name;
                    }
                }
                else
                {
                    imgBackground.Source = new BitmapImage(new Uri(this.BaseUri, "Assets/Backgrounds/wonderwoman.png"));
                    LblCharacter.Text = "Wonder Woman :)";
                }
                };
                backgroundtimer.Start();
    }
    }

Mainpage.Xaml View

Page
    x:Class="GetMarvelCharacter.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:GetMarvelCharacter"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock x:Name="LblError" TextWrapping="Wrap" TextAlignment="Center" Margin="447,125,0,0" Width="265" Height="78" FontSize="12" HorizontalAlignment="Left" VerticalAlignment="Top"/>
        <Image Name="imgBackground" RequestedTheme="Light" Opacity="0.5" Height="480" Width="800" HorizontalAlignment="Center" VerticalAlignment="Center" />
        <TextBlock x:Name="LblCharacter" TextWrapping="Wrap" TextAlignment="Center" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>

    </Grid>
</Page>

References

Full Code on Github

Json2csharp Json to C# was used to generate the attributes for the Model Class. You can simulate your applications json results by using the API documentation on the Marvel API and getting back test results in json format. To make a Model for any other Marvel API call, simply copy and paste the json results into json2csharp, copy to a C# class, and build the model similar to how I have it above.

Visual Studio Community

Marvel API

Channel 9