0
using System;
using System.Text;

namespace ConsoleApp7
{
    class Program
    {
        static void Main(string[] args)
        {
            YourClient client = new YourClient();
            
            client.Put();
        }

        public class YourClient
        {
            private readonly HttpClient _client;

            public YourClient()
            {
                _client = new HttpClient();
            }

            public async Task Put() // must be async
            {
                using (var request = new HttpRequestMessage(HttpMethod.Put, "https://api.minecraftservices.com/minecraft/profile/name/egg"))
                {
                    request.Headers.Add("Authorization", "Bearer token");
                    request.Content = new StringContent("body", Encoding.UTF8, "content-type");

                    using (var response = await _client.SendAsync(request))
                    {
                        var data = await response.Content.ReadAsStringAsync();
                        var code = response.StatusCode;
                        Console.WriteLine(Convert.ToString(code));

                        // do something with data
                    }
                }
            }
        }
    }
}

I'm not getting any output and I don't know why. I'm trying to print the response code of the request but nothing is output, is it to do with my method?

I have tried printing hi after Client.Put() and it was printed, so I know that my code is actually running, I just don't know why it isn't printing the status code ...

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Hud Kad
  • 9
  • 1
  • 7
    You are not `await`ing the `Put()` method call and because of that your program just exits before the task is completed and before any output can be written to console. Research [Asynchronous programming with async and await](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/). – Prolog Jun 25 '22 at 19:34

1 Answers1

0

The excellent comment by Prolog points out one of two issues. If your Console app is built on < C# 7.1 you will need a workaround to prevent the app from exiting (before the request has time to process) so in this case add Console.ReadKey() as the very last line. This will spin the message loop until you hit a key. But this is not the main issue and I would like to offer a couple of debugging tips.

The big issue is this:

  • If I run your code, your http request is failing and is throwing a System.FormatException
  • Usually this type of exception is not set to Break when Thrown. (You can verify this by looking in the Exception Settings window.) Unfortunately, this is giving you a silent failure in this case, so you must take matters into your own hands to observe it.

Suggestions for debugging your code

  1. Use a try-catch block around any code that has any likelihood of failing.

  2. Use System.Diagnostics.Debug.Assert which will cause your program to break on a line if any condition expression evaluates to false (but only when you're running in Debug mode not Release mode).

  3. Add output statements to trace execution. Using Debug.WriteLine will send messages to the Output window (but again, only in Debug mode). Alternatively, since we have a Console app here, I'm using the main app window to output trace statements.

Example using 1-3:

public async Task Put() // must be async
{
    Console.WriteLine("Begin Put()");
    try
    {
        using (var request = new HttpRequestMessage(HttpMethod.Put, "https://api.minecraftservices.com/minecraft/profile/name/egg"))
        {
            request.Headers.Add("Authorization", "Bearer token");
            request.Content = new StringContent("body", Encoding.UTF8, "content-type");

            using (var response = await _client.SendAsync(request))
            {
                var data = await response.Content.ReadAsStringAsync();
                var code = response.StatusCode;
                Console.WriteLine(Convert.ToString(code));

                // do something with data
            }
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.Assert(condition: false, message: ex.Message);
    }
    Console.WriteLine("End Put()");
}

Now, if I run the code it will break and show what the problem is.

Exception and Assert

  1. Use the Exception Settings window to turn on all exceptions (if in doubt). Now the code will break on the exact line that is the problem.

Break when Thrown

  1. Verify that you are Setting Authorization Header of HttpClient correctly as this may be part of the root cause of the exception.

Finally, if you continue after the Debug.Assert you will see the following text in your console which will confirm whether your Put method has had a chance to complete or not.

console output

Hope these suggestions help you solve this problem and future ones!


// This workaround for C# versions below 7.1 attempts to 
// mimic an `async Main` method. 
static void Main(string[] args)
{
    RunAsync();
    Console.ReadKey();
}

private static async void RunAsync()
{
    YourClient client = new YourClient();
    // Put() should be awaited inside an async method
    await client.Put();
}
IVSoftware
  • 5,732
  • 2
  • 12
  • 23
  • I should mention that **I completely agree** with @Prolog that `Put()` _should be awaited_. The problem is if you try and mark `Main` as `async` then it gives you **Program does not contain a static 'Main' method suitable for an entry point** error at runtime. So in this particular case we spin-and-wait. – IVSoftware Jun 26 '22 at 14:52
  • 1
    Since C# 7.1 `Main()` method can be made asynchronous and can return a `Task`, thus you can do `await client.Put()` in the `Main()` method. [Official documentation reference](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.1/async-main). Also, [avoid async void](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#avoid-async-void) when possible. – Prolog Jun 26 '22 at 15:06
  • **Agree** with your second point also. In C# 7.1 + it should be `async Task RunAsync()` but you have the option to explicitly discard it with `_ = await RunAsync()` in that case, does that sound right? – IVSoftware Jun 26 '22 at 15:12
  • `_ = await RunAsync()` will generate an error since `Task` returned from `RunAsync()` does not return value so there is no value to discard. Have a look at this great introduction to [Asynchronous programming](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/). – Prolog Jun 26 '22 at 15:20
  • Indeed, I should have said that `_ = RunAsync()` discards the Task and disappears the "Because the call is not awaited..." suggestion whereas `_ = await RunAsync()` discards the _result_ of a Task. Many great changes C# but people like me who are mostly supporting legacy apps (i.e. "more than a day old") have to divide our time and even perhaps pick our battles. Conversations like this one are definitely helpful and I appreciate you providing links to the very latest info. I also edited answer to be more correct in light of. – IVSoftware Jun 26 '22 at 16:16