Pragmatic Mash-Ups Andrew Filev Microsoft Certified Architect Murano Software Building POC of Web 2.0 application in one day with AJAX, Virtual Earth and Linq
Idea, scope Implementation –Collecting data Getting web page Getting data with regular expressions Using REST based XML pages –Selecting data: Linq, DLinq, XLinq –Displaying data Displaying Virtual Earth map Adding pushpins Filtering pushpins Future directions
Idea To help people find their house by: Mashing-up real estate sales ads with house valuation service and displaying ones which are priced below valuation on the map
Example listing
Scope This presentation is not covering important aspects of the whole application: –Valuation might be incorrect –How to get permission for data and valuation It is focused on technologies It’s about POC in a a day, not about release in a …
Implementation at the high level Take listings Add valuation information Provide web-site to access this information
Getting web page WebClient client = new WebClient(); string pageContent = client.DownloadString(url)
Getting data: HTML+Regex yahoo map Regular Expression yahooStreetAddressParameter.Value = yahoo_address
Getting data: REST+XML XDocument doc = new XDocument(); doc.Load(String.Format(“ bservice/GetSearchResults.htm?address= {0}&citystatezip={1}”, yahooStreetAddress, yahooCityStateZip)); var result = doc.Descendants(“address”).First().Element(“street”); streetParameter.Value = (string)result;
.NET Language Integrated Query Integration into programming language and IDE Select, from, where, into, orderby … XML (XLinq) and SQL (DLinq) support
DLinq: Basics New item->DLinqObjects Drag table from Server Explorer Write queries in C# _context = new DataContext(connString) var results = from listing in _context.Listings where listing.Longitude <=… select listing; foreach (var item in results){ …item.Latitude… }
DLinq: Attributes [System.Data.DLinq.Table(Name="Listings")] public partial class Listing : System.Data.DLinq.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged … [System.Data.DLinq.Column(Name="YahooStreetAddress", Storage="_YahooStreetAddress", DBType="varchar NOT NULL")] public virtual string YahooStreetAddress { get {return this._YahooStreetAddress;} set { if ((this._YahooStreetAddress != value)) { this.OnPropertyChanging("YahooStreetAddress"); this._YahooStreetAddress = value; this.OnPropertyChanged("YahooStreetAddress"); }
Tip: how to pass connection string public partial class masterDataContext : System.Data.DLinq.DataContext { public masterDataContext(string connString) : base(connString) { }
DLinq+XLinq XDocument xmlDoc=new XDocument( new XDeclaration("1.0", "utf-8",null), new XElement("root", from listing in _context.Listings where listing.Longitude … select new XElement("item", new XAttribute("id",listing.ID), new XAttribute("lat",listing.Latitude), new XAttribute("long",listing.Longitude), new XAttribute("price",listing.Price), new XAttribute("est",listing.Zestimate), new XAttribute("details",listing.Street))));
Displaying map var map=null; function DrawMap(){ map = new VEMap('myMap'); map.LoadMap(new VELatLong(34, ), 10,'r', false); GetPushpins(); } …
AJAX request var xhr = null; function CreateXHR(){ var xhr; try{xhr = new ActiveXObject("Microsoft.XMLHTTP");} catch(e){try{xhr=new ActiveXObject("Msxml2.XMLHTTP");} catch(ex){xhr = false;}} if (!xhr && typeof XMLHttpRequest != 'undefined') {xhr = new XMLHttpRequest();} return xhr; } function GetPushpins() { map.DeleteAllPushpins(); xhr = CreateXHR(); xhr.onreadystatechange = ProcessPushpins; xhr.open("GET", "getInfo.aspx?action=getLocations"); xhr.send(); }
Tip: move pushpins with visible area function DrawMap(){…map.AttachEvent("onchangeview", GetPushpins);} function GetPushpins(){ … mapDiv = document.getElementById('myMap'); leftTopLatLong = map.PixelToLatLong(0, 0); rightBottomLatLong = map.PixelToLatLong(mapDiv.offsetWidth, mapDiv.offsetHeight); hr.open( "GET", "getInfo.aspx?action=getVisibleLocations&left=" + leftTopLatLong.Longitude + "&top=" + leftTopLatLong.Latitude + "&right=" + rightBottomLatLong.Longitude + "&bottom=" + rightBottomLatLong.Latitude); … } public string GetItems(RectangleF LatLongBounds) { … from listing in _context.Listings where listing.Longitude = LatLongBounds.Bottom
What might be next Atlas RSS consumption Intelligent data reload Adding/changing sources of data
Useful links