JokeAPI icon indicating copy to clipboard operation
JokeAPI copied to clipboard

C# Advanced Example Bugs

Open krchome opened this issue 5 years ago • 13 comments

Describe the bug

There are three errors (runtime) that are being encountered to run the code as a .NET Core console application as per the attached screenshot image

Steps to reproduce

Steps to reproduce the unwanted behavior: Open up Visual Studio 2019 Community Create .NET Core console application Copy and paste the code shown on the C# Advanced code example in the Program.cs Run the application

Expected behavior

It should run without error

Screenshots

If applicable and possible, add screenshots to help explain your problem. image

Additional information

  • OS: [e.g. Windows 10 - Build 1803]
  • C#

Code snippet

If this bug is caused by a piece of code, send the code right here and mark the line where it is caused.
I only know JavaScript, C++ and C#, but I can probably interpret other languages. `using System; using System.Threading.Tasks; using System.Net.Http; using Newtonsoft.Json; // Install with NuGet Package Manager: https://www.nuget.org/packages/Newtonsoft.Json/12.0.3?_src=template

namespace TestHttpRequest { class Program { static async Task Main(string[] args) { Joke randomJoke = await GetJokeAdvanced(); (Err1: Cannot implicitly convert type void to T.JokeestHttpRequest) if (randomJoke.type == "single") { Console.WriteLine(randomJoke.joke); } else { Console.WriteLine(randomJoke.setup); System.Threading.Thread.Sleep(3000); Console.WriteLine(randomJoke.delivery); } }

    public async static Task GetJokeAdvanced()
    {
        const string baseUrl = "https://jokeapi.dev";
        string[] categories = { "Programming", "Miscellaneous", "Pun", "Spooky", "Christmas" };
        string[] parameters = {
            "blacklistFlags=nsfw,religious,racist,sexist",
            "idRange=0-100"
        };
        string requestUrl = $"{baseUrl}/joke/{string.Join(",", categories)}?{string.Join("&", parameters)}";
        Joke randomJoke;

        using (var httpClient = new HttpClient())
        {
            var json = await httpClient.GetStringAsync(requestUrl);
            randomJoke = JsonConvert.DeserializeObject(json);**(Err2: Cannot implicity convert type object to TestHttpRequest.Joke)**
        }

        return randomJoke; (Err3: Since Program.GetJokeAdvanced() is an async method that returns Task, a return keyword must not be followed by an object expression)
    }
} 

public class Joke
{
    public string type { get; set; }
    public string joke { get; set; }
    public string setup { get; set; }
    public string delivery { get; set; }
    public int id { get; set; }
    public Flags flags { get; set; }
}


public class Flags
{
    public bool nsfw { get; set; }
    public bool religious { get; set; }
    public bool political { get; set; }
    public bool racist { get; set; }
    public bool sexist { get; set; }
}

} `

Additional context

I have taken the exact code snippet from your website for Joke API. I hope you will be able to easily replicate the issues on Windows 10 and VS 2019 (I have used version 8.1)

krchome avatar Jan 20 '21 20:01 krchome

After some research, I have now the correct code below: `using System; using System.Threading.Tasks; using System.Net.Http; using Newtonsoft.Json; // Install with NuGet Package Manager: https://www.nuget.org/packages/Newtonsoft.Json/12.0.3?_src=template

namespace TestHttpRequest { class Program { static async Task Main(string[] args) { Joke randomJoke = await GetJokeAdvanced(); if (randomJoke.type == "single") { Console.WriteLine(randomJoke.joke); } else { Console.WriteLine(randomJoke.setup); System.Threading.Thread.Sleep(3000); Console.WriteLine(randomJoke.delivery); } }

    public async static Task<Joke> GetJokeAdvanced()
    {
        const string baseUrl = "https://jokeapi.dev";
        string[] categories = { "Programming", "Miscellaneous", "Pun", "Spooky", "Christmas" };
        string[] parameters = {
            "blacklistFlags=nsfw,religious,racist,sexist",
            "idRange=0-100"
        };
        string requestUrl = $"{baseUrl}/joke/{string.Join(",", categories)}?{string.Join("&", parameters)}";
        Joke randomJoke;

        using (var httpClient = new HttpClient())
        {
            var json = await httpClient.GetStringAsync(requestUrl);
            randomJoke = JsonConvert.DeserializeObject<Joke>(json);
        }

        return randomJoke;
    }
}

public class Joke
{
    public string type { get; set; }
    public string joke { get; set; }
    public string setup { get; set; }
    public string delivery { get; set; }
    public int id { get; set; }
    public Flags flags { get; set; }
}


public class Flags
{
    public bool nsfw { get; set; }
    public bool religious { get; set; }
    public bool political { get; set; }
    public bool racist { get; set; }
    public bool sexist { get; set; }
}

} ` Please correct the code in your website (https://sv443.net/jokeapi/v2/?ref=apilist.fun#examples)after running and satisfying yourself as above. So closing the issue.

krchome avatar Jan 20 '21 20:01 krchome

@krchome did you close this issue on accident?

Sv443 avatar Jan 20 '21 21:01 Sv443

I closed this issue as I could sort out the issue I raised earlier (with all screenshots) and when I edited it with the intention to close it accidentally I created another issue. Hence I thought to close this newly accidentally created issue and edit the original one saying I am closing it now. Hope I make sense :-)

krchome avatar Jan 20 '21 21:01 krchome

Sure. Thanks for explaining 😃

Sv443 avatar Jan 20 '21 22:01 Sv443

Can you please update the code as there were two minor errors which I have corrected and tested fine. The correction are commented in the code below :

using System;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;   // Install with NuGet Package Manager: https://www.nuget.org/packages/Newtonsoft.Json/12.0.3?_src=template

namespace TestHttpRequest
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Joke randomJoke = await GetJokeAdvanced();
            if (randomJoke.type == "single")
            {
                Console.WriteLine(randomJoke.joke);
            }
            else
            {
                Console.WriteLine(randomJoke.setup);
                System.Threading.Thread.Sleep(3000);
                Console.WriteLine(randomJoke.delivery);
            }
        }

        public async static Task<Joke> GetJokeAdvanced()  // **Changed to return Task<Joke>** 
        {
            const string baseUrl = "https://jokeapi.dev";
            string[] categories = { "Programming", "Miscellaneous", "Pun", "Spooky", "Christmas" };
            string[] parameters = {
                "blacklistFlags=nsfw,religious,racist,sexist",
                "idRange=0-100"
            };
            string requestUrl = $"{baseUrl}/joke/{string.Join(",", categories)}?{string.Join("&", parameters)}";
            Joke randomJoke;

            using (var httpClient = new HttpClient())
            {
                var json = await httpClient.GetStringAsync(requestUrl);
                randomJoke = JsonConvert.DeserializeObject<Joke>(json); **// Changed to incude Joke class after DeserializeObject method**
            }

            return randomJoke;
        }
    }

    public class Joke
    {
        public string type { get; set; }
        public string joke { get; set; }
        public string setup { get; set; }
        public string delivery { get; set; }
        public int id { get; set; }
        public Flags flags { get; set; }
		public bool safe { get; set; }
    }


    public class Flags
    {
        public bool nsfw { get; set; }
        public bool religious { get; set; }
        public bool political { get; set; }
        public bool racist { get; set; }
        public bool sexist { get; set; }
		public bool explicit { get; set; }
    }
}

krchome avatar Jan 21 '21 02:01 krchome

@krchome I've added the explicit flag and safe property, could you please verify that I didn't mess anything up?

Sv443 avatar Jan 21 '21 20:01 Sv443

@krchome I've added the explicit flag and safe property, could you please verify that I didn't mess anything up? Everything still works fine except make 'e' capital in explicit as 'Explicit' since 'explicit' is a C# keyword

I am creating an MVC ASP.NET Core 5.0 app and wish to create the 'Try it out here' as an MVC view that generates the request URL and passes it to a JokesController to get the response (as we get here on your website).

Now since three of the filters: Categories, Response (format), and Joke Amount are not included in the Joke class, I am wondering if I need to create a ViewModel including these as properties and then use that model for model binding with the server-side action method code? Any thoughts from you will be appreciated.

Thanks for creating this API for public use free of cost.

krchome avatar Jan 21 '21 23:01 krchome

Sorry but I don't know a thing about ASP.NET and what you described doesn't ring a bell to me.

Thanks for creating this API for public use free of cost.

Thank you for using it :)

Sv443 avatar Jan 22 '21 12:01 Sv443

Changed it to the following now and it seems to be working great:

using System;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;   // Install with NuGet Package Manager: https://www.nuget.org/packages/Newtonsoft.Json/12.0.3?_src=template

namespace TestHttpRequest
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.Write("\n");

            Joke randomJoke = await GetJoke();
            if (randomJoke.type == "single")
            {
                Console.WriteLine(randomJoke.joke);
            }
            else
            {
                Console.WriteLine(randomJoke.setup);
                Console.WriteLine("...");
                System.Threading.Thread.Sleep(3000);
                Console.WriteLine(randomJoke.delivery);
            }

            Console.Write("\n");
        }

        public async static Task<Joke> GetJoke()
        {
            const string baseUrl = "https://v2.jokeapi.dev";
            string[] categories = { "Programming", "Miscellaneous", "Pun" };
            string[] parameters = {
                "blacklistFlags=nsfw,religious,racist,sexist",
                "idRange=0-100",
                "safe-mode",
                "lang=en"
            };
            string requestUrl = $"{baseUrl}/joke/{string.Join(",", categories)}?{string.Join("&", parameters)}";
            Joke randomJoke;

            using (var httpClient = new HttpClient())
            {
                var json = await httpClient.GetStringAsync(requestUrl);
                randomJoke = JsonConvert.DeserializeObject<Joke>(json);
            }

            return randomJoke;
        }
    }

    public class Joke
    {
        public string type { get; set; }
        public string joke { get; set; }
        public string setup { get; set; }
        public string delivery { get; set; }
        public Flags flags { get; set; }
        public int id { get; set; }
        public bool safe { get; set; }
        public string lang { get; set; }
    }

    public class Flags
    {
        public bool nsfw { get; set; }
        public bool religious { get; set; }
        public bool political { get; set; }
        public bool racist { get; set; }
        public bool sexist { get; set; }
        public bool @explicit { get; set; } // use @ since "explicit" is a reserved keyword
    }
}

Sv443 avatar Jun 25 '21 06:06 Sv443

On your website: https://sv443.net/jokeapi/v2/#getting-started

The two C# lines:

public async static Task GetJokeAdvanced()

and

randomJoke = JsonConvert.DeserializeObject(json);

should instead read:

public async static Task<Joke> GetJokeAdvanced()

and

randomJoke = JsonConvert.DeserializeObject<Joke>(json);

You likely just need to convert the < and > in your HTML to &lt; and &gt;.

fmccown avatar Nov 11 '21 19:11 fmccown

Thanks for bringing that up. Could you elaborate on why it's necessary? I've run the code and it works fine, and the docs show both as valid (Task class without generic type and with a generic)
As for the JSON deserialization, the type should be implicitly passed onto the deserialization function shouldn't it?

Also note that the code on the documentation is outdated. To see the latest version you can use the staging server at https://stage.jokeapi.dev/ or see this comment which should still be up to date iirc.

Sv443 avatar Nov 11 '21 21:11 Sv443

The code on the staging server has a GetJoke() method with Task<Joke> and compiles fine. If I leave off the <Joke> from the GetJoke() method, Visual Studio complains about the return statement trying to return a value. An async method must specify a Task data type if the method returns a value.

I don't think the deserialization function knows the type automatically... it must be explicitly stated, or you have to typecast:

randomJoke = (Joke) JsonConvert.DeserializeObject(json);

fmccown avatar Nov 11 '21 23:11 fmccown

Alright thanks, I'll take a look at this again soon.

Sv443 avatar Nov 12 '21 20:11 Sv443