This article describes the practical approach to integrate Google Maps API, Autocomplete Places API, and Geocode API with the ASP.NET MVC 5 application.
Recently, I was working on a project in which I had to select the venue by applying the autocomplete place API, and on the basis of the venue, I had to get the country, state, city, zip code, latitude, and longitude. If user entered the unknown venue then on the basis of Country and Zip code, state and city would be saved.
To complete the requirement, I have used the following Google APIs,
- Autocomplete Place API
- Map API
- Geocode API
In this article, we will create an ASP.NET MVC application and integrate the above APIs with our web application. So, let’s start the procedure with the following sections,
- Creating ASP.NET MVC Web Application
- Working with Application
Creating ASP.NET MVC Application
In this section, we’ll create the ASP.NET Web application with the help of MVC project template in Visual Studio 2013. Follow the steps below:
Step 1
Open the Visual Studio and click on a new project and create a new ASP.Net Web Application named “GooglePlaceMVCSample”
Figure 1: Creating Web Application
Step 2
Select the MVC project template from the next “One ASP.Net wizard”
Figure 2: MVC Project Template
That’s it. Your MVC application is created.
Working with Application
In this section, we will work with the existing “HomeController” and “About.cshtml” page or you can create new controller and view to work with the application. At first we will create a new model so that we can bind the view with the mode and pass some data from the controller to view with the help of model.
Let’s start with the following procedure:
Step 1
Right click on the “Models” folder and add a new class named “Venue”,
Figure 3: Adding class to Model
- public class Venue
- {
- #region Properties
- public int Id { get; set; }
- [Required(ErrorMessage = "Name is required")]
- public string Name { get; set; }
- [Required(ErrorMessage = "ZipCode is required")]
- public string ZipCode { get; set; }
- [Required(ErrorMessage = "Country is required")]
- public string Country { get; set; }
- public string CountryName { get; set; }
- [Required(ErrorMessage = "State is required")]
- public string State { get; set; }
- [Required(ErrorMessage = "City is required")]
- public string City { get; set; }
- public float Latitude { get; set; }
- public float Longitude { get; set; }
- public List<Country> Countries { get; set; }
- public string CountryCode { get; set; }
- #endregion
- }
-
- public class Country
- {
- #region Properties
- public int CountryId { get; set; }
- public string CountryName { get; set; }
- public string MapReference { get; set; }
- public string CountryCode { get; set; }
- public string CountryCodeLong { get; set; }
- #endregion
- }
Step 2
Add a new class as named “CountryModel” and add the following code,
- public class CountryModel
- {
- #region DatabaseMethod
- public List<T> ConvertTo<T>(DataTable datatable) where T : new()
- {
- List<T> Temp = new List<T>();
- try
- {
- List<string> columnsNames = new List<string>();
- foreach (DataColumn DataColumn in datatable.Columns)
- columnsNames.Add(DataColumn.ColumnName);
- Temp = datatable.AsEnumerable().ToList().ConvertAll<T>(row => getObject<T>(row, columnsNames));
- return Temp;
- }
- catch
- {
- return Temp;
- }
-
- }
- public T getObject<T>(DataRow row, List<string> columnsName) where T : new()
- {
- T obj = new T();
- try
- {
- string columnname = "";
- string value = "";
- PropertyInfo[] Properties;
- Properties = typeof(T).GetProperties();
- foreach (PropertyInfo objProperty in Properties)
- {
- columnname = columnsName.Find(name => name.ToLower() == objProperty.Name.ToLower());
- if (!string.IsNullOrEmpty(columnname))
- {
- value = row[columnname].ToString();
- if (!string.IsNullOrEmpty(value))
- {
- if (Nullable.GetUnderlyingType(objProperty.PropertyType) != null)
- {
- value = row[columnname].ToString().Replace("$", "").Replace(",", "");
- objProperty.SetValue(obj, Convert.ChangeType(value, Type.GetType(Nullable.GetUnderlyingType(objProperty.PropertyType).ToString())), null);
- }
- else
- {
- value = row[columnname].ToString();
- objProperty.SetValue(obj, Convert.ChangeType(value, Type.GetType(objProperty.PropertyType.ToString())), null);
- }
- }
- }
- }
- return obj;
- }
- catch
- {
- return obj;
- }
- }
- #endregion
-
- SqlConnection con;
- SqlDataAdapter adap;
- DataTable dt;
- SqlCommand cmd;
- public CountryModel()
- {
- string conn = ConfigurationManager.ConnectionStrings["CountryConnectionString"].ConnectionString;
- con = new SqlConnection(conn);
- }
-
- public List<Country> GetCountries()
- {
- List<Country> countries = new List<Country>();
- try
- {
- con.Open();
- adap = new SqlDataAdapter();
- dt = new DataTable();
- cmd = new SqlCommand("GetCountries", con);
- cmd.CommandType = CommandType.StoredProcedure;
-
- adap.SelectCommand = cmd;
- adap.Fill(dt);
- countries = ConvertTo<Country>(dt);
- }
- catch (Exception x)
- {
-
- }
- finally
- {
- cmd.Dispose();
- con.Close();
- }
- return countries;
- }
- }
Step 3
Open “Web.Config” and add the following connection string code for database,
- <add name="CountryConnectionString" connectionString="data source=server name,1436;database=Sample;user id=sa;password=123456;MultipleActiveResultSets=True" providerName="System.Data.SqlClient"/>
Note
Change the connection string as per your credentials.
Step 4
Open “HomeController” and edit the code with the following highlighted code,
- public ActionResult About()
- {
- ViewBag.Message = "Your application description page.";
- List<Country> objCountry = new List<Country>();
- CountryModel model = new CountryModel();
- objCountry = model.GetCountries();
- return View(new Venue { Countries = objCountry });
- }
Step 5
Now edit the “About.cshtml” page with the following code,
- @model GooglePlaceMvcSample.Models.Venue
- @{
- ViewBag.Title = "About";
- }
- <h2>@ViewBag.Title.</h2>
- <h3>@ViewBag.Message</h3>
-
- <p>Use this area to provide additional information.</p>
- <script src="~/Scripts/jquery-2.2.3.js"></script>
- <script src="~/Scripts/jquery-2.2.3.min.js"></script>
- <script src="~/Scripts/jquery-ui-1.11.4.js"></script>
- <script src="~/Scripts/jquery-ui-1.11.4.min.js"></script>
- <script src="~/Scripts/jquery.validate.js"></script>
- <div class="row">
- <div class="col-md-8">
- <div class="form-group">
- @Html.LabelFor(m => m.Name, new { @class = "col-md-2 control-label" })
- <div class="col-md-10">
- @Html.TextBoxFor(m => m.Name, new { @class = "form-control", id = "TextBoxVenueLocation" })
- @Html.ValidationMessageFor(m => m.Name, "", new { @class = "text-danger" })
- @Html.HiddenFor(m => m.Id, new { @id = "EventVenueId" })
- </div>
- </div>
- <div class="form-group">
- @Html.LabelFor(m => m.Country, new { @class = "col-md-2 control-label" })
- <div class="col-md-10">
- @Html.DropDownListFor(m => m.CountryCode, new SelectList(Model.Countries, "CountryCode", "CountryName"), "Choose Country", new { @class = "selectBox form-control ", @id = "DropDownListCounties" })
- @Html.HiddenFor(m => m.CountryName, new { @id = "HdnCountryName" })
- @Html.ValidationMessageFor(m => m.Country, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- @Html.LabelFor(m => m.ZipCode, new { @class = "col-md-2 control-label" })
- <div class="col-md-10">
- @Html.TextBoxFor(m => m.ZipCode, new { @class = "form-control", id = "TextBoxZipCode", maxlength = 6 })
- @Html.ValidationMessageFor(m => m.ZipCode, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- @Html.LabelFor(m => m.State, new { @class = "col-md-2 control-label" })
- <div class="col-md-10">
- @Html.TextBoxFor(m => m.State, new { @class = "form-control", id = "TextBoxState" })
- @Html.ValidationMessageFor(m => m.State, "", new { @class = "text-danger" })
- </div>
- </div>
- <div class="form-group">
- @Html.LabelFor(m => m.City, new { @class = "col-md-2 control-label" })
- <div class="col-md-10">
- @Html.TextBoxFor(m => m.City, new { @class = "form-control", id = "TextBoxCity" })
- @Html.ValidationMessageFor(m => m.City, "", new { @class = "text-danger" })
- </div>
- </div>
- @Html.HiddenFor(m => m.Latitude, new { @id = "EventVenueLatitude" })
- @Html.HiddenFor(m => m.Longitude, new { @id = "EventVenueLongitude" })
- </div>
- </div>
- </div>
- </div>
Step 6
Open the Content-> Site.css and add the following code in the bottom,
- .selectBox{width:295px;height:38px;padding: 0 0 0 9px;}
- select option{width:255px;}
Step 7
Save the application and debug it.
Figure 4: Model Binded Vew in MVC 5
Creating Google Autocomplete Place API Key
At first for accessing the autocomplete place API, you have to create an API Key to access that places API url. To create an API key, follow the steps below:
Step 1
Go to
Google Developer Console,
Step 2
Login with your Gmail account and click on Continue to “Create New Project”,
Figure 5: Creating New Project in Google APIs
Step 3
Enter the name for API Key as shown below,
Figure 6: Create Server API Key
Step 4
Now, you can copy your API Key from the next wizard.
Figure 7: API key Info
Step 5
Open WebConfig in your project and add a key in the AppSettings tab as shown in the code below,
- <add key="GooglePlaceAPIKey" value="Your API Key"></add>
Note
Please change the value with your API Key.
Adding Google Autocomplete Place API
In this section we will apply the Google autocomplete place API. We will return the response in the json format so that it is easy to convert the json result to list. We can also use XML format to get the API result.
Now start with the following steps,
Step 1
At first we will add a class in our model. Add the following code in your Venue class,
- public class Prediction
- {
- public string description { get; set; }
- public string id { get; set; }
- public string place_id { get; set; }
- public string reference { get; set; }
- public List<string> types { get; set; }
- }
- public class RootObject
- {
- public List<Prediction> predictions { get; set; }
- public string status { get; set; }
- }
Step 2
Now just add the following key in your WebConfig file for accessing the place api url.
- <add key="GooglePlaceAPIUrl" value="https://maps.googleapis.com/maps/api/place/autocomplete/json?input={0}&types=geocode&language=en&key={1}"/>
Step 3
Now create an action method in the HomeController with the help of the following code,
-
-
-
-
-
- [HttpGet, ActionName("GetEventVenuesList")]
- public JsonResult GetEventVenuesList(string SearchText)
- {
- string placeApiUrl = ConfigurationManager.AppSettings["GooglePlaceAPIUrl"];
-
- try
- {
- placeApiUrl = placeApiUrl.Replace("{0}", SearchText);
- placeApiUrl = placeApiUrl.Replace("{1}", ConfigurationManager.AppSettings["GooglePlaceAPIKey"]);
-
- var result = new System.Net.WebClient().DownloadString(placeApiUrl);
- var Jsonobject = JsonConvert.DeserializeObject<RootObject>(result);
-
- List<Prediction> list = Jsonobject.predictions;
-
- return Json(list, JsonRequestBehavior.AllowGet);
- }
- catch (Exception ex)
- {
- return Json(ex.Message, JsonRequestBehavior.AllowGet);
- }
- }
Step 4
Now open the “About.cshtml” page and add the following script,
- <script type="text/javascript">
- $(function () {
- $("#TextBoxVenueLocation").autocomplete({
- source: function (request, response) {
- $.ajax({
- url: "@Url.Action("GetEventVenuesList", "Home")",
- data: { SearchText: request.term },
- dataType: "json",
- type: "GET",
- success: function (data) {
- if (data.length == 0) {
- $('#EventVenueId').val("");
- $('#VenueLocationMesssage').show();
- return false;
- }
- else {
- response($.map(data, function (item) {
- return {
- label: item.description,
- value: item.place_id
- }
- }));
- }
- },
- error: function (x, y, z) {
- alert('error');
- }
- });
- },
- messages: {
- noResults: "", results: ""
- },
- select: function (event, ui) {
- $('#TextBoxVenueLocation').val(ui.item.label);
- $('#EventVenueId').val(ui.item.value);
- return false;
- }
- }).autocomplete("widget").addClass("CitiesAutocomplete");
- });
- </script>
- @section Scripts {
- @Scripts.Render("~/bundles/jqueryval")
- }
Step 5
Now add the following css code in the Site.css file,
- .CitiesAutocomplete{list-style:none;background:#fbfbfb;border:1px solid #5f5f5f!important;width:350px !important;position:absolute;z-index:10000;border-top:none;min-height:25px;max-height:250px;overflow: auto;cursor:pointer; padding: 4px 0;}
- .CitiesAutocomplete li{padding: 2px 6px;}
- .CitiesAutocomplete li:hover{background-color:#9eeffe; }
Step 6
Now run the application and you will get the location as you type in the Name textbox. As you type in the textbox, the places will be displayed,
Figure 8: Autocomplete Place API Result
We have successfully completed the add Place API. Now, we’ll move to the next section.
Adding Google Map API for Place Details In this section, we will get all the place details like Country, State, City, Address, Zipcode, Latitude or Longitude etc by using the Google MAP API. We have to pass the PlaceId which will get from the Autocomplete API places. We will get the API result in the XML format and fetch the necessary details from the API result.
Start with the following steps Step 1
Add the following API url in the webconfig file,
- <add key="GooglePlaceDetailsAPIUrl" value="https://maps.googleapis.com/maps/api/place/details/xml?placeid={0}&key={1}"/>
Step 2
Add the following methods in the “HomeController”:
-
-
-
-
-
- [HttpGet, ActionName("GetVenueDetailsByPlace")]
- public JsonResult GetVenueDetailsByPlace(string placeId)
- {
- string placeDetailsApi = ConfigurationManager.AppSettings["GooglePlaceDetailsAPIUrl"];
- try
- {
- Venue ven = new Venue();
- placeDetailsApi = placeDetailsApi.Replace("{0}", placeId);
- placeDetailsApi = placeDetailsApi.Replace("{1}", ConfigurationManager.AppSettings["GooglePlaceAPIKey"]);
-
- var result = new System.Net.WebClient().DownloadString(placeDetailsApi);
-
- var xmlElm = XElement.Parse(result);
- ven = GetAllVenueDetails(xmlElm);
-
- return Json(ven, JsonRequestBehavior.AllowGet);
- }
- catch (Exception ex)
- {
- return Json(ex.Message, JsonRequestBehavior.AllowGet);
- }
- }
-
-
-
-
-
- private Venue GetAllVenueDetails(XElement xmlElm)
- {
- Venue ven = new Venue();
- List<string> c = new List<string>();
- List<string> d = new List<string>();
-
- var status = (from elm in xmlElm.Descendants()
- where
- elm.Name == "status"
- select elm).FirstOrDefault();
-
-
- if (status.Value.ToLower() == "ok")
- {
-
-
- var addressResult = (from elm in xmlElm.Descendants()
- where
- elm.Name == "address_component"
- select elm);
-
- var locationResult = (from elm in xmlElm.Descendants()
- where
- elm.Name == "location"
- select elm);
-
- foreach (XElement item in locationResult)
- {
- ven.Latitude = float.Parse(item.Elements().Where(e => e.Name.LocalName == "lat").FirstOrDefault().Value);
- ven.Longitude = float.Parse(item.Elements().Where(e => e.Name.LocalName == "lng").FirstOrDefault().Value);
- }
-
- foreach (XElement element in addressResult)
- {
- string type = element.Elements().Where(e => e.Name.LocalName == "type").FirstOrDefault().Value;
-
- if (type.ToLower().Trim() == "locality")
- {
- ven.City = element.Elements().Where(e => e.Name.LocalName == "long_name").Single().Value;
- }
- else
- {
- if (type.ToLower().Trim() == "administrative_area_level_2" && string.IsNullOrEmpty(ven.City))
- {
- ven.City = element.Elements().Where(e => e.Name.LocalName == "long_name").Single().Value;
- }
- }
- if (type.ToLower().Trim() == "administrative_area_level_1")
- {
- ven.State = element.Elements().Where(e => e.Name.LocalName == "long_name").Single().Value;
- }
- if (type.ToLower().Trim() == "country")
- {
- ven.Country = element.Elements().Where(e => e.Name.LocalName == "long_name").Single().Value;
- ven.CountryCode = element.Elements().Where(e => e.Name.LocalName == "short_name").Single().Value;
- if (ven.Country == "United States") { ven.Country = "USA"; }
- }
- if (type.ToLower().Trim() == "postal_code")
- {
- ven.ZipCode = element.Elements().Where(e => e.Name.LocalName == "long_name").Single().Value;
- }
- }
- }
- xmlElm.RemoveAll();
- return ven;
- }
Note
In the above code, there are two methods, the first one is used to call the api and get the api result in the xml format. Second method is used to get all the required place details like Country, State, City, Latitude and Longitude. You can fetch the details from the json result also.
Step 3
In the “About.cshtml” page, update the autocomplete method with the help of the highlighted code below:
Change the select method in autocomplete - select: function (event, ui) {
- $('#TextBoxVenueLocation').val(ui.item.label);
- $('#EventVenueId').val(ui.item.value);
- GetVenueDetailsByPlaceId(ui.item.value);
- return false;
- }
Add the following function in the script - function GetVenueDetailsByPlaceId(PlaceId) {
- $.ajax({
- url: '@Url.Action("GetVenueDetailsByPlace", "home")',
- dataType: "json",
- data: {
- placeId: PlaceId
- },
- type: "GET",
- async: false,
- error: function (xhr, status, error) {
- var err = eval("(" + xhr.responseText + ")");
- toastr.error(err.message);
- },
- success: function (data) {
- $('#TextBoxZipCode').val(data.ZipCode);
- $('#DropDownListCounties option:selected').text(data.Country);
- $('#TextBoxState').val(data.State);
- $('#TextBoxCity').val(data.City);
- $('#EventVenueLatitude').val(data.Latitude);
- $('#EventVenueLongitude').val(data.Longitude);
- },
- beforeSend: function () {
- $("#divProcessing").show();
- }
- });
- }
Step 4
Now with the help of this code, we will fetch the place details and display the details in the textbox. Run the application and search for any genuine place.
Figure 9: Searching Place using Autocomplete API
Now select the place,
Figure 10: Place Details using MAP Place API
That’s it with this section. Now we’ll move to further sections.
Adding Google Geocode API
In this section, we’ll use the Google Geocode API to get the place details in case there are no matching records displayed in the autocomplete API result. So in that case, we can get the place details by providing the Zip code and country as a region in the api.
Let’s start with the following steps:
Step 1
Add the following API url in the Web.Config file,
- <add key="GoogleGeocodeAPIUrl" value="https://maps.googleapis.com/maps/api/geocode/xml?address={0}®ion={1}&key={2}"/>
Step 2
Add the following method in the “HomeController”,
-
-
-
-
-
-
- [HttpGet, ActionName("GetVenueDetailsByZipCode")]
- public JsonResult GetVenueDetailsByZipCode(string zipCode, string region)
- {
- string geocodeApi = ConfigurationManager.AppSettings["GoogleGeocodeAPIUrl"];
- try
- {
- Venue ven = new Venue();
- geocodeApi = geocodeApi.Replace("{0}", zipCode);
- geocodeApi = geocodeApi.Replace("{1}", region);
- geocodeApi = geocodeApi.Replace("{2}", ConfigurationManager.AppSettings["GooglePlaceAPIKey"]);
-
- var result = new System.Net.WebClient().DownloadString(geocodeApi);
-
- var xmlElm = XElement.Parse(result);
- ven = GetAllVenueDetails(xmlElm);
- return Json(ven, JsonRequestBehavior.AllowGet);
- }
- catch (Exception ex)
- {
- return Json(ex.Message, JsonRequestBehavior.AllowGet);
- }
- }
Step 3
Now add the following function in the “About.cshtml” page,
-
- $("#TextBoxZipCode").keydown(function (e) {
-
- if ($.inArray(e.keyCode, [46, 8, 9, 27, 13, 110, 190]) !== -1 ||
-
- ((e.keyCode == 65 || e.keyCode == 86 || e.keyCode == 67) && (e.ctrlKey === true || e.metaKey === true)) ||
-
- (e.keyCode >= 35 && e.keyCode <= 40)) {
-
- return;
- }
-
- if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
- $("#TextBoxZipCode").val('');
- e.preventDefault();
- return false;
- }
- });
-
- var timer;
- $("#TextBoxZipCode").on('keyup', function (event) {
- clearTimeout(timer);
- timer = setTimeout(function () {
- if ($('#DropDownListCounties option:selected').val() == '' && $("#TextBoxZipCode").val() != '') {
- alert('Country is required');
- $("#TextBoxZipCode").val('');
- return false;
- }
- else {
- $.ajax({
- url: '@Url.Action("GetVenueDetailsByZipCode", "home")',
- dataType: "json",
- data: {
- zipCode: $("#TextBoxZipCode").val(), region: $("#DropDownListCounties").val()
- },
- type: "GET",
- async: false,
- error: function (xhr, status, error) {
- var err = eval("(" + xhr.responseText + ")");
- toastr.error(err.message);
- },
- success: function (data) {
- $('#TextBoxZipCode').val(data.ZipCode);
- $('#TextBoxState').val(data.State);
- $('#TextBoxCity').val(data.City);
- $('#EventVenueLatitude').val(data.Latitude);
- $('#EventVenueLongitude').val(data.Longitude);
- },
- beforeSend: function () {
- $("#divProcessing").show();
- }
- });
- }
- }, 500);
- });
Note
With the help of the above code, the user can only enter numbers in the zip code textbox and after entering the number, the API result will be displayed. I have made the country required because in many cities zip codes arethe same so in that case, region (country) will be helpful to get the particular result.
Note about API KEY
If your API key will not get the result or there is some error generated to get the result then you go
here and create the new API key for Geocode API.
Step 4
Now run the application and search the place, if the place is not listed in the api result, just select the country at first and then enter the zip code and you will get the result from the Geocode API.
Figure 11: Place Details using Geocode API
That’s it for this article.
Summary
This article described how we can use different Google provided APIs and how to integrate Google APIs in the ASP.Net MVC Application.