0

Due to the fact that I need to convert this C# dll into a tlp file to be called from Visual Basic 6, I need avoid using external dependencies. I have used RestSharp to consume a WebAPI by doing the following (working):

using RestSharp;
using Newtonsoft.Json;

..

public string GetToken (string Key, string Password) {

  var client = new RestClient (BaseUrl + "auth/GetToken");
  var request = new RestRequest (Method.POST);
  request.AddHeader ("cache-control", "no-cache");
  request.AddHeader ("Content-Type", "application/json");
  Dictionary<string, string> data = new Dictionary<string, string> {
    { "APIKey", Key },
    { "APIPassword", Password }
};
var dataJSON = JsonConvert.SerializeObject (data);
request.AddParameter ("undefined", dataJSON, ParameterType.RequestBody);

IRestResponse response = client.Execute (request);

GetTokenResults g = JsonConvert.DeserializeObject<GetTokenResults> (response.Content); 

return g.Token;
}

where GetTokenResults was a struct that contained a declaration for the string Token. I want to achieve this same functionality without using RestSharp. Here is my unsuccessful attempt:

using System.Net.Http;
using System.Net.Http.Headers;

..

public async void GetToken (string Key, string Password) {

  var client = new HttpClient ( );
  client.DefaultRequestHeaders.Accept.Clear ( );
  client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue ("application/json"));
  client.BaseAddress = new Uri (BaseUrl + "auth/GetToken");

  Dictionary<string, string> data = new Dictionary<string, string> {
  { "APIKey", Key },
  { "APIPassword", Password }
};
  var dataJSON = JsonConvert.SerializeObject (data);

  var content = new StringContent (dataJSON, Encoding.UTF8, "application/json");

  var response = await client.PostAsync ("", content);

}

I am unclear on how to achieve the same results (send API key and password, return token as string) using HttpClient as I did using RestSharp earlier. Anything that can point me in the right direction is greatly appreciated!

3
  • 1
    Take a look at the following Q&A Commented Jan 23, 2019 at 21:25
  • @ToddMenier I have upvoted your answer, but due to the fact that I have less than 15 reputation, it is not publicly displayed Commented Jan 25, 2019 at 16:38
  • No problem, I appreciate you accepting it :) Commented Jan 25, 2019 at 19:57

2 Answers 2

0

I think you got stung by this issue. In short, the URI in client.BaseAddress needs a slash at the end of it.

However, I wouldn't simply add it, I'd consider doing it a little different. Presumably your BaseUrl already has a trailing slash, given you're appending "auth/GetToken" to it. I'd do it this way:

client.BaseAddress = new Uri(BaseUrl);
...
var response = await client.PostAsync("auth/GetToken", content);

As you can see, HttpClient fits very cleanly with how your code is already set up, i.e. you have a "base" address with a trailing slash and you want to append to it for a specific call.

That should get you un-stuck to this point. The next thing you'll need to tackle is deserializing the JSON response so you can get the token out of it. It's similar to how you did it in RestSharp, except that response.Content is not a string in the HttpClient world, so you need one more step to get that:

var json = await response.Content.ReadAsStringAsync();
GetTokenResults g = JsonConvert.DeserializeObject<GetTokenResults>(json);
return g.Token;

Last thing you'll need to do to get this to compile is change the method signature to:

public async Task<string> GetTokenAsync

One final note: you are now in the async world, and that's a good thing, but you need to know how to use it correctly or you could end up with deadlocks and other mysterious bugs. In short, don't block on async code by calling .Result or .Wait() anywhere up the call stack. That's by far most common mistake people make. Use async/await all the way down.

Sign up to request clarification or add additional context in comments.

2 Comments

This solution worked perfectly! Out of curiosity, is there any reason why appending the URI in var response is any better than including it all in the BaseAddress?
Well, for one thing, you already have a BaseAddress and a relative endpoint in 2 pieces, which fits the HttpClient usage pattern of "create client with base address, call specific endpoint" perfectly, so why concat them? But more importantly, if you were to reuse the same client to call different endpoints (which you should do as much as possible), it's set up well to do that.
0

I think you are missing first parameter in the method PostAsync i.e. requestUri=Client.BaseAddress (see my implementation below).

Try with this first, if did not work, read below. I have a little different implementation where I passed client.BaseAddress as first parameter and I am passing my content as ByteArrayContent. In my case I have to pass my content as "application/x-www-form-urlencoded" excerpt of my code:

        var buffer = Encoding.UTF8.GetBytes(content);
        var byteContent = new ByteArrayContent(buffer);
        //as I can't send JSON, probably, you can skip as it's already JSON
        byteContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");  
       //requestUri=client.BaseAddress          
        await client.PostAsync(requestUri, byteContent).ConfigureAwait(false); 

We have somewhat different need but I think you are pretty close. If it does not help, write me I will share my code. After reading the comment, I would like to share how I have made my HttpClient. The code is as it is:

 using (var client = CreateMailClientForPOST($"{BaseUrl}/"))
        {
           //removed code, you can call above code as method like
           var response= await client.DoThingAsAsync($"{client.BaseAddress}, content").ConfigureAwait(false);
        }

protected HttpClient CreateMailClientForPOST(string resource)
    {
        var handler = new HttpClientHandler();
        if (handler.SupportsAutomaticDecompression)
        {
            handler.AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate;
        }

        var client = new HttpClient(handler)
        {

            BaseAddress = new Uri($"https://api.address.com/rest/{resource}")
        };
        return client;
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.