Step 3–Augmented Reality, Windows 8, and Cloud Computing–How to implement with real code (Implementing the Cloud Back-End)


Title Description Link
Augmented Reality applications need a Web Service Back-End. Here is a 90-Day No obligation, totally free offer to use Windows Azure as your web service for Windows 8 Clients. You get: Compute / 750 small compute hours per month, Web sites / 10 web sites, Mobile services / 10 mobile services, Relational database / 1 SQL database, SQL reporting / 100 hours per month, Storage / 35GB with 50,000,000 storage transactions, Bandwidth / unlimited inbound & 25GB outbound, CDN / 20GB outbound with 500,000 transactions, Cache / 128MB, Service bus / 1,500 relay hours and 500,000 messages https://www.microsoft.com/click/services /Redirect2.ashx?CR_CC=200114759image
Step 0: What we will build. Augmented Reality, Windows 8, and Cloud Computing–How to implement with real code High level introduction to our finished application. https://blogs.msdn.com/b/brunoterkaly/archive/2012 /11/05/step-0-what-we-will-build- augmented-reality-windows-8-and-cloud-computing-how-to-implement-with-real-code.aspx#
Step 1–Augmented Reality, Windows 8, and Cloud Computing–How to implement with real code Introduction. What is Augmented Reality https://blogs.msdn.com/b/brunoterkaly/archive/2012/10/29/ step-1-augmented-reality-windows-8-and-cloud-computing- how-to-implement-with-real-code.aspx#
Step 2–Augmented Reality, Windows 8, and Cloud Computing–How to implement with real code Building the first part of our Azure back-end. https://blogs.msdn.com/b/brunoterkaly/archive/2012/10/30/ step-2-augmented-reality-windows-8-and- cloud-computing-how-to-implement-with-real-code.aspx#
Step 3–Augmented Reality, Windows 8, and Cloud Computing–How to implement with real code (Implementing the Cloud Back-End) This post provides all source code and explanation for the Azure back-end. This is the back-end for the augmented reality Windows 8 Client. https://blogs.msdn.com/b/brunoterkaly/archive/2012/11/05 /step-3-augmented-reality-windows-8-and-cloud-computing-how- to-implement-with-real-code-implementing-the-cloud-back-end.aspx#
Step 4–Augmented Reality, Windows 8, and Cloud Computing–How to implement with real code ... This post provides all source code and explanation for the Windows 8 Client (Augmented Reality Demo). The augmented reality Windows 8 Client calls into the Azure back-end described in step 3 above. https://blogs.msdn.com/b/brunoterkaly/archive/2012/11/06/ step-4-augmented-reality-windows-8-and-cloud-computing-how-to-implement-with-real-code-implementing-the- windows-8-client.aspx#
Source Code - Web Service Back End This is the Windows Azure Project that Windows 8 Clients call into https://sdrv.ms/Qoqb1J
Source Code - Windows 8 Client This is the Augmented Reality Windows 8 Client https://sdrv.ms/T38uBC

This is the finished augmented reality client.
image

  1. I have completed the code. Now it is time to blog about it.
  2. Notice that it has augmented reality data overload on top of a live photo
  3. It also has a satellite image
  4. You can use the GPS simulator to change locations
    • My system doesn't have a GPS device and yours probably does not either
  5. The information displayed is a mash-up of the Google Maps and information from the National Oceanic and Atmospheric Administration
  6. I will provide all source code.

A zoom-in of the augmented reality data
002

  1. A little better resolution to see what is happening.

This is a Windows Azure Back-end
003

  1. It is hosted in a Microsoft Data Center
  2. The image above is running locally (in an emulator)
  3. This running application can be scaled to meet any demand by Windows 8 clients
  4. The style of Azure application is (MVC Web API), described in future posts

The application architecture
image

  1. We will build a Windows 8 Client in a future post
    • That is where the augmented reality is actually taking place
  2. Our front end web services tier supports our Windows 8 Client
    • We will deploy this tier to a Microsoft Data Center
  3. The Application Services Tier will be Google Maps and the National Oceanic Atmospheric Agency (NOAA)
  4. This could be architected for even greater scale.
    • You could leverage message queues and background processes (worker roles)
  5. It does currently leverage threading for parallel look ups of data mash-ups
    • This means I call Google Maps and NOAA at the same time using .NET Tasks
  6. The next step is to finish building the cloud server.
  7. From there I will show the code behind the Windows 8 client

Focusing on the Cloud Back-End
image

  1. In Step 2 you could see how to create:
    • A Windows Azure Cloud Project with:

                1 MVC 4 Web Role

                Web Role Type = ASP.NET Web API


Starting the server
image

  1. It is a Windows Azure Cloud app
  2. It was previously blogged about here
  3. But we need to add more to this project.

Visual Studio 2012 - Solution Explorer
image

  1. You can see one solution with two projects:
    • Project 1: Location_WebRole
      • This is where we do all the work, adding code
    • Project 2: LocationWebService
      • This is the configuration project that allows us to scale our application once we deploy it to the cloud.

How to build the Azure Cloud Application Back-End
image

  1. We are going to do 3 things here:
    • Modify Existing Files
    • Add a folder to hold our code
    • Add new classes
  2. Modify Files
    • ValuesController.cs
  3. Add Folder
    • HelperObjects
  4. Add classes (HelperObjects)
    • CityFromGps.cs
    • DataExtractor.cs
    • LocationInfo.cs

ValuesController.cs
image

  1. This is the entry point for clients making http calls
  2. We only need one method in there.
    • The Get() method responds to Windows 8 client requests
ValuesController.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using Location_WebRole.HelperObjects; namespace Location_WebRole.Controllers {     public class ValuesController : ApiController     {         // location contains lat/long, "37.788345,-122.404679", for example         public LocationInfo Get(string location)         {             string[] columns = location.Split(',');             CityFromGps city = new CityFromGps();             return city.ReverseGeoLoc(columns[1], columns[0]);         }       } }
  Code Walkthrough
Line 11 ValuesController.cs was built by Visual Studio when we created the project. It is the entry point for Windows 8 client requests.
Line 14 We have just one Get() method. It is executed automatically by Windows 8 clients. The Windows client will issue the commands in Table A
Line 16 Split the GPS coordinates. columns[0] will be 37.785530, and columns[1] will be -122.405672
Line 17 Our helper class that actually does all the processing
Line 18 Return the JSON answers back to the Windows 8 Client
  Table A
Our cloud project running in emulator https://127.0.0.1:81/api/values?location=37.785530,-122.405672
Our cloud project running in a Microsoft Data Center https://locationwebservice.cloudapp.net/api/values?location=37.785530,-122.405672

The main workhorse - CityFromGps.cs
011

  1. This class does most of the hard work.
  2. It uses concurrent programming techniques to conduct data mash-ups.
CityFromGps.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Net.Http.Formatting; using System.Text; using System.Threading.Tasks; using System.Xml; using Location_WebRole.HelperObjects; namespace Location_WebRole.Controllers {     // My custom string manipulator. Nows how to parse all the XML structures     public class CityFromGps     {         // Method that does all the lookups based on longitude and latitude.         public LocationInfo ReverseGeoLoc(string longitude, string latitude)         {             // Return data is LocationInfo             LocationInfo loc_info = new LocationInfo();             DataExtractor de = new DataExtractor(); // a helper class to make this threading code readable             loc_info.longitude = longitude;             loc_info.latitude = latitude;             try             {                 //                 // Get Data                 //                 XmlDocument[] xmldocs = new XmlDocument[3] { new XmlDocument(), new XmlDocument(), new XmlDocument() };                 Task<string>[] tasks = new Task<string>[3]                 {                     Task<string>.Factory.StartNew(() =>                         {                             xmldocs[0].Load("http://maps.googleapis.com/maps/api/elevation/xml?locations=" + latitude + "," + longitude + "&sensor=false");                             XmlNodeList weatherList = xmldocs[0].SelectNodes("//ElevationResponse/result");                             loc_info.elevation = (Convert.ToDouble(weatherList[0]["elevation"].InnerText) * 3.2808399).ToString();                             return "";                         }),                     Task<string>.Factory.StartNew(() =>                         {                             // Get Transit and Neighborhood Info                             xmldocs[1].Load(string.Format("http://maps.googleapis.com/maps/api/geocode/xml?latlng={0},{1}&sensor=false", latitude, longitude));                             loc_info.bus_and_neighborhood = de.GetTransitAndNeighborhood(xmldocs[1]);                             return "";                         }),                     Task<string>.Factory.StartNew(() =>                         {                             // Get Weather Info                             xmldocs[2].Load(string.Format("http://graphical.weather.gov/xml/sample_products/browser_interface/ndfdXMLclient.php?lat={0}&lon={1}&product=time-series&maxt=maxt&mint=mint", latitude, longitude));                             loc_info.max_temp = de.GetMaxTemp(xmldocs[2]);                             loc_info.min_temp = de.GetMinTemp(xmldocs[2]);                             return "";                         })                 };                 //Block until all tasks complete. This is much faster.                 Task.WaitAll(tasks);                 return loc_info;             }             catch (Exception ex)             {                 loc_info.error = "(Location lookup failed: ) " + ex.Message;                 return loc_info;             }         }     } }
  Code Walkthrough
Lines 1 to 10 Needed using statements
Line 15 CityFromGps class that we've added
Line 19 The ReverseGeoLoc() method. It returns JSON-formatted data for LocationInfo (a class we still need to add). It takes two parameters, logitude and latitude. It will perform a number of look ups against other web services, such as Google Maps and NOAA (NOAA - National Oceanic and Atmospheric Administration)
Lines 22 and 23 Instantiate our helper objects. LocationInfo will contain the results of our data lookups. It will hold temperature, elevation, city, etc.
Line 33 The XmlDocument objects that will be used for the lookups against web services
Lines 37, 44, 51 3 Tasks (concurrent threads if enough cores) are launched, working in parallel, performing lookups against web services.
Lines 40-41, 47-48, 54-56 The actual lookups. This where the actual call to Google Maps and NOAA takes place.
Line 61 Wait for all tasks to complete. This line ensures that we continue only after all 3 tasks have completed.
Line 62 Return the LocationInfo object, which is now populated with data. The ASP.NET Web API automatically makes this a JSON formatted object.

DataExtractor.cs and LocationInfo.cs
013

  1. DataExtractor.cs abstracts the complexity of parsing XML and getting the answers we need
    • Such as max temp, min temp, elevation, etc
  2. LocationInfo.cs represents the data going back to the Windows 8 client
    • It is in JSON format.
DataExtractor.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Xml; namespace Location_WebRole.Controllers {     public class DataExtractor     {         public string GetTransitAndNeighborhood(XmlDocument doc)         {             string result = "";             bool foundneighborhood = false;             bool foundbus = false;             XmlNodeList xnList = doc.SelectNodes("//GeocodeResponse/result/address_component");             foreach (XmlNode xn in xnList)             {                 try                 {                     switch (xn["type"].InnerText)                     {                         //Add whatever you are looking for below                         case "bus_station":                             {                                 if (foundbus)                                     break;                                 if (result != "")                                     result += ", ";                                 result += "Bus: " + xn["long_name"].InnerText;                                 foundbus = true;                                 break;                             }                         case "neighborhood":                             {                                 if (foundneighborhood)                                     break;                                 if (result != "")                                     result += ", ";                                 result += "Neighborhood: " + xn["long_name"].InnerText + " (" + xn["short_name"].InnerText + ")";                                 foundneighborhood = true;                                 break;                             }                         default:                             break;                     }                 }                 catch (Exception e)                 {                 }             }             return result;         }         internal string GetMaxTemp(XmlDocument doc)         {             XmlNodeList xnList = doc.SelectNodes("//dwml/data/parameters/temperature");             return xnList[0]["value"].InnerText; // offset 0 is max temps         }         internal string GetMinTemp(XmlDocument doc)         {             XmlNodeList xnList = doc.SelectNodes("//dwml/data/parameters/temperature");             return xnList[1]["value"].InnerText; // offset 1 is min temps         }     } }
  Code Walkthrough
Line 11 The method that returns the bus stop and neighborhood information.
Line 60 The method that returns the max temperature info from NOAA
Line 65 The method that returns the min temperature info from NOAA
LocationInfo.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Net.Http.Formatting; using System.Web; namespace Location_WebRole.HelperObjects {     public class LocationInfo     {         // Data we will lookup         public string latitude { get; set; }         public string longitude { get; set; }         public string elevation { get; set; }         public string bus_and_neighborhood { get; set; }         public string max_temp { get; set; }         public string min_temp { get; set; }         public string error { get; set; }     } }
  Code Walkthrough
Line 11 Our LocationInfo structure. This will be returned back to the Windows 8 client, populated with data. The ASP.NET Web API will automatically convert this object to JSON format.

Conclusion

    The next series of posts will focus on the Windows 8 client.