HttpClient GetAsync with query string

26.7k Views Asked by At

I am using Google's GeoCoding API. I have two methods where one works and the other doesn't and I can't seem to figure out why:

string address = "1400,Copenhagen,DK";
string GoogleMapsAPIurl = "https://maps.googleapis.com/maps/api/geocode/json?address={0}&key={1}";
string GoogleMapsAPIkey = "MYSECRETAPIKEY";
string requestUri = string.Format(GoogleMapsAPIurl, address.Trim(), GoogleMapsAPIkey);

// Works fine                
using (var client = new HttpClient())
{
    using (HttpResponseMessage response = await client.GetAsync(requestUri))
    {
        var responseContent = response.Content.ReadAsStringAsync().Result;
        response.EnsureSuccessStatusCode();
    }
}

// Doesn't work
using (HttpClient client = new HttpClient())
{
    client.BaseAddress = new Uri("https://maps.googleapis.com/maps/api/", UriKind.Absolute);
    client.DefaultRequestHeaders.Add("key", GoogleMapsAPIkey);

    using (HttpResponseMessage response = await client.GetAsync("geocode/json?address=1400,Copenhagen,DK"))
    {
        var responseContent = response.Content.ReadAsStringAsync().Result;
        response.EnsureSuccessStatusCode();
    }
}

My last method with GetAsync where I am sending a query string doesn't work and I am in doubt why it is so. When I introduce BaseAddress on the client the GetAsync somehow doesn't send to the correct URL.

2

There are 2 best solutions below

9
Giovanni Esposito On BEST ANSWER

Ciao, the problem is related with key parameter on URL. Change your code like this:

using (HttpClient client = new HttpClient())
{
   client.BaseAddress = new Uri("https://maps.googleapis.com/maps/api/");
   
   using (HttpResponseMessage response = await client.GetAsync("geocode/json?address=1400,Copenhagen,DK&key=" + GoogleMapsAPIkey))
    {
       var responseContent = response.Content.ReadAsStringAsync().Result;
       response.EnsureSuccessStatusCode();
    }
}

As google sheets said:

After you have an API key, your application can append the query parameter key=yourAPIKey to all request URLs. The API key is safe for embedding in URLs; it doesn't need any encoding.

4
aepot On

I don't suggest adding API key into globals. Maybe you'll need to send some HTTP request outside of the API and the key will be leaked.

Here's the example that works.

using Newtonsoft.Json;
public class Program
{
    private static readonly HttpClient client = new HttpClient();
    private const string GoogleMapsAPIkey = "MYSECRETAPIKEY";

    static async Task Main(string[] args)
    {
        client.BaseAddress = new Uri("https://maps.googleapis.com/maps/api/");

        try
        {
            Dictionary<string, string> query = new Dictionary<string, string>();
            query.Add("address", "1400,Copenhagen,DK");
            dynamic response = await GetAPIResponseAsync<dynamic>("geocode/json", query);
            Console.WriteLine(response.ToString());
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
        Console.ReadKey();
    }

    private static async Task<string> ParamsToStringAsync(Dictionary<string, string> urlParams)
    {
        using (HttpContent content = new FormUrlEncodedContent(urlParams))
            return await content.ReadAsStringAsync();
    }

    private static async Task<T> GetAPIResponseAsync<T>(string path, Dictionary<string, string> urlParams)
    {
        urlParams.Add("key", GoogleMapsAPIkey);
        string query = await ParamsToStringAsync(urlParams);
        using (HttpResponseMessage response = await client.GetAsync(path + "?" + query, HttpCompletionOption.ResponseHeadersRead))
        {
            response.EnsureSuccessStatusCode();
            string responseText = await response.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<T>(responseText);
        }
    }
}