简体   繁体   中英

Need help converting my RestSharp code to use HttpClient instead

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!

I think you are missing first parameter in the method PostAsync ie 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;
    }

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, ie 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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM