/* * Method: GetPlacesDetailWithOptions * * Description: This method can be used to query the Places API for details regarding places with a * specific place_id. The optional parameters can be used to determine the language of the response * as well as what infromation is returned. If no fields are provided, then the query returns all * available fields. * * Parameters: * - place_id (String): A String identifier that uniquely identifies a place. This is returned as part * of the response from the Place Search functions. For more details about place_id: * https://developers.google.com/places/web-service/place-id * * - region_code (String): This is an OPTIONAL parameter, that indicates the region code, specified as a * ccTLD format. This is used to influence the query's results but relevant results outside the * region may also be included. * - fields (List<PlacesDetailFields>): OPTIONAL parameter. This is a list of details you wish to get * about the places that match the query. If the list is empty or null, then the Places API will * return all available details by default. * - language_code (String): OPTIONAL parameter indicating the language in which results will be returned. * By default this is set to English. List of supported languages and their codes: * https://developers.google.com/maps/faq#languagesupport * * - APIKey (String): Implicity required paramter which should be set through the constructor when * creating an object of this class. For more details about the Google API Key please see: * https://developers.google.com/places/web-service/get-api-key * * Return: The method returns a tuple of two items. The first is an object of PlacesDetailResponse * which contains all available details for the place. The second element is a ResponseStatus object * indicating the status of the query along with the appropiate HTTP code. The tuple wrapped in a Task<> * because the method makes Asynchronous HTTP requests to the Places API. */ public async Task <Tuple <PlacesDetailResponse, ResponseStatus> > GetPlaceDetailsWithOptions(String place_id, String region_code = "", String language_code = "", String session_token = "", List <PlacesDetailFields> fields = null) { if (BasicFunctions.isEmpty(APIKey)) { return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, PlacesStatus.MISSING_API_KEY)); } if (BasicFunctions.isEmpty(place_id)) { return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, PlacesStatus.MISSING_PLACE_ID)); } // Creating the HTTP query url String HTTP_query = $"details/json?placeid={place_id}"; // Appending any optional fields that are set if (!BasicFunctions.isEmpty(region_code)) { HTTP_query += $"®ion={region_code}"; } if (!BasicFunctions.isEmpty(language_code)) { HTTP_query += $"&language={language_code}"; } if (!BasicFunctions.isEmpty(session_token)) { HTTP_query += $"&sessiontoken={session_token}"; } if (fields != null && fields.Count != 0) { HTTP_query += $"&fields={BasicFunctions.getPlacesDetailFieldsListString(fields)}"; } HTTP_query += $"&key={APIKey}"; // Setting up the request header to indicate that the request body will be in json httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // Making an asynchronous HTTP GET request to the Places API and collecting the output HttpResponseMessage response = await httpClient.GetAsync(HTTP_query); Stream stream = await response.Content.ReadAsStreamAsync(); StreamReader streamReader = new StreamReader(stream); String response_str = streamReader.ReadToEnd(); // Similar two-step hop as in prior functions if (response.IsSuccessStatusCode) { try { PlacesDetailResponse resultList = JsonConvert.DeserializeObject <PlacesDetailResponse>(response_str); if (!resultList.Status.Equals("OK")) { // If the response status from the API is not OK, then we try to return the most appropriate Error ResponseStatus status = PlacesStatus.ProcessErrorMessage(resultList.Status, resultList.Error_message); return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, status)); } else if (resultList.Result == null) { // If the response provides an empty response set, then we return the ZERO_RESULTS (204) error return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, PlacesStatus.ZERO_RESULTS)); } else { return(new Tuple <PlacesDetailResponse, ResponseStatus>(resultList, PlacesStatus.OK)); } } catch (JsonSerializationException e) { // If the deserialization of the response fails, then we return an error Debug.WriteLine("Exception: " + e.StackTrace); return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, PlacesStatus.DESERIALIZATION_ERROR)); } } else { // If the response status from the API is not a success, then we return an error using the data returned return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, new ResponseStatus((int)response.StatusCode, response.ReasonPhrase))); } }
/* * Method: GetPlacesDetail * * Description: This method can be used to query the Places API for details regarding places with a * specific place_id. The place_id is usually obtained from the response of a Place Search function. * * Parameters: * - place_id (String): A String identifier that uniquely identifies a place. This is returned as part * of the response from the Place Search functions. For more details about place_id: * https://developers.google.com/places/web-service/place-id * * - APIKey (String): Implicity required paramter which should be set through the constructor when * creating an object of this class. For more details about the Google API Key please see: * https://developers.google.com/places/web-service/get-api-key * * Return: The method returns a tuple of two items. The first is an object of PlacesDetailResponse * which contains all available details for the place. The second element is a ResponseStatus object * indicating the status of the query along with the appropiate HTTP code. The tuple wrapped in a Task<> * because the method makes Asynchronous HTTP requests to the Places API. */ public async Task <Tuple <PlacesDetailResponse, ResponseStatus> > GetPlaceDetails(String place_id) { if (BasicFunctions.isEmpty(APIKey)) { return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, PlacesStatus.MISSING_API_KEY)); } if (BasicFunctions.isEmpty(place_id)) { return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, PlacesStatus.MISSING_PLACE_ID)); } // Creating the HTTP query url String HTTP_query = $"details/json?placeid={place_id}&key={APIKey}"; // Setting up the request header to indicate that the request body will be in json httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // Making an asynchronous HTTP GET request to the Places API and collecting the output HttpResponseMessage response = await httpClient.GetAsync(HTTP_query); Stream stream = await response.Content.ReadAsStreamAsync(); StreamReader streamReader = new StreamReader(stream); String response_str = streamReader.ReadToEnd(); Console.WriteLine(response_str); /* * Here we do a two-step hop again to achieve the appropriate return value: * We use the response string (response_str) from above and attempt to convert it back from json to * NearbySearchResultList, the expected return object for a successful query. This produces one of * two possibilities: * 1. If the response string is not a json of the NearbySearchResultList class, then we either get * a JsonSerializationException or an empty list. In this case we print out the response and * return null (Will improve this to return an appropriate error code). * 2. If the response string is as expected a json of NearbySearchResultList, then things go * smoothly and we return that. */ if (response.IsSuccessStatusCode) { try { PlacesDetailResponse resultList = JsonConvert.DeserializeObject <PlacesDetailResponse>(response_str); if (!resultList.Status.Equals("OK")) { // If the response status from the API is not OK, then we try to return the most appropriate Error ResponseStatus status = PlacesStatus.ProcessErrorMessage(resultList.Status, resultList.Error_message); return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, status)); } else if (resultList.Result == null) { // If the response provides an empty response set, then we return the ZERO_RESULTS (204) error return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, PlacesStatus.ZERO_RESULTS)); } else { return(new Tuple <PlacesDetailResponse, ResponseStatus>(resultList, PlacesStatus.OK)); } } catch (JsonSerializationException e) { // If the deserialization of the response fails, then we return an error Console.WriteLine("Exception: " + e.StackTrace); return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, PlacesStatus.DESERIALIZATION_ERROR)); } } else { // If the response status from the API is not a success, then we return an error using the data returned return(new Tuple <PlacesDetailResponse, ResponseStatus>(null, new ResponseStatus((int)response.StatusCode, response.ReasonPhrase))); } }
/* * Method: GetPlacesPhotos * * Description: This method can be used to get a photo based on a photo reference returned as part of a * PlacesSearch or PlacesDetail response. If the photo exists, then the method will save the photo at * the desired directory address. * * Parameters: * - photoReference (String): A String identifier that uniquely identifies a photo. This is returned as * part of the response for a PlacesSearch or PlacesDetail queries. * - fileDestination (String): An absolute or relative path address of the desired location where the * photo should be stored. * * One of the following two parameters is required: * - maxHeight (int): This is an OPTIONAL parameter which indicates the maximum height of the image. * - maxWidth (int): This is an OPTIONAL parameter which indicates the maximum width of the image. * * - APIKey (String): Implicity required paramter which should be set through the constructor when * creating an object of this class. For more details about the Google API Key please see: * https://developers.google.com/places/web-service/get-api-key * * Return: The method returns a tuple of two items. The first is a String. If the query is successful * then the string returns the directory location where the photo was stored. If the query fails for any * reason then, the string is returned as null. The second element is a ResponseStatus object indicating * the status of the query along with the appropiate HTTP code. The tuple wrapped in a Task<> because * the method makes Asynchronous HTTP requests to the Places API. */ public async Task <Tuple <String, ResponseStatus> > GetPlacesPhotos(String photoReference, String fileDestination, int maxHeight = 0, int maxWidth = 0) { if (BasicFunctions.isEmpty(APIKey)) { return(new Tuple <String, ResponseStatus>(null, PlacesStatus.MISSING_API_KEY)); } if (BasicFunctions.isEmpty(photoReference)) { return(new Tuple <String, ResponseStatus>(null, PlacesStatus.MISSING_PHOTO_REFERENCE)); } if (maxHeight <= 0 && maxWidth <= 0) { return(new Tuple <string, ResponseStatus>(null, PlacesStatus.MISSING_HEIGHT_WIDTH)); } if (BasicFunctions.isEmpty(fileDestination)) { return(new Tuple <string, ResponseStatus>(null, PlacesStatus.MISSING_FILE_DESTINATION)); } // Creating the HTTP query url String HTTP_query = $"photo?photoreference={photoReference}"; if (maxHeight > 0) { HTTP_query += $"&maxheight={maxHeight}"; } if (maxWidth > 0) { HTTP_query += $"&maxwidth={maxWidth}"; } HTTP_query += $"&key={APIKey}"; // Setting up the request header to indicate that the request body will be in json httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // Making an asynchronous HTTP GET request to the Places API and collecting the output HttpResponseMessage response = await httpClient.GetAsync(HTTP_query); Stream stream = await response.Content.ReadAsStreamAsync(); if (response.IsSuccessStatusCode) { // The following block of code is borrowed from https://stackoverflow.com/a/2368180 using (BinaryReader reader = new BinaryReader(stream)) { Byte[] lnByte = reader.ReadBytes(1 * 1024 * 1024 * 10); try { using (FileStream lxFS = new FileStream(fileDestination, FileMode.Create)) { lxFS.Write(lnByte, 0, lnByte.Length); // End of borrowed code } } catch (ArgumentException e) { // If we get an exception, then the directory path provided is likely invalid and we return that error Debug.WriteLine(e.StackTrace); return(new Tuple <String, ResponseStatus>(null, PlacesStatus.INVALID_FILE_LOCATION)); } catch (IOException e) { Debug.WriteLine(e.StackTrace); if (e.Message.ToLower().Contains("could not find a part of the path")) { return(new Tuple <string, ResponseStatus>(null, PlacesStatus.INVALID_FILE_LOCATION)); } return(new Tuple <String, ResponseStatus>(null, PlacesStatus.INTERNAL_SERVER_ERROR)); } } } else { return(new Tuple <string, ResponseStatus>(null, PlacesStatus.ProcessErrorMessage(response.StatusCode.ToString(), response.ReasonPhrase))); } // If there are no errors, then we return the directory address where the photo was stored return(new Tuple <string, ResponseStatus>(fileDestination, PlacesStatus.OK)); }