ClipTheTrip.com - How I Built This
Clipthetrip.com is a fun, free crowd sourced destination guides. From a data modeling perspective it has a pretty simple object interaction. There is Location object, there is CLIP object, there is photo object and a user object. MongoDB was used as a data store so objects were quite denormalized instead of a referential model.
Some of the technologies and API used for building the site is as follows:
- MongoDB
- .NET MVC3.0
- .NET 4.0 web optimization library for Js and CSS minimizing and combining
- jQuery Plugins
- Wookmark
- jQuery Lightbox
- qTips
- GMap3 for google maps
- jQuery Fullscreen for homepage background
- Imagesloaded
- Autosuggest for location suggestion
- Plupload for uploading images
- Tablesorter
- CookieControl from the pesky Europe cookie law
- jQuery Reject
-
External API's
- Weather information using Accuweather
- Currency using Webservicex service
- Business search using Bing
- Image processing using SimpleDotImage library
- Generating offline PDF's using wkhtmltopdf
- HtmlAgilityPack for screen scrapping
- Amazon SES for email
As part of this article I am sharing code snippets of how I extracted information from external API's and other smaller code snippets. Since most part of the site is just CRUD operations, I feel it would be a waste to explain the code structure or architecture (considering architecture is quite simple!)
Currency data from Webservicex.net
Example page: http://www.clipthetrip.com/city/london
1 2 3 4 5 6 7 8 | var xElement = System.Xml.Linq.XElement.Load( "http://www.webservicex.net/CurrencyConvertor.asmx/ConversionRate?FromCurrency=USD&ToCurrency=" + code); //code being 3 letter code like USD, INR etc. var cur = decimal .Parse(xElement.Value).ToString( "#.##" ); jsonResult.Data = new { c = cur, code = code }; return jsonResult; |
Business information from Bing
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 | var html = new WebClient().DownloadString( "http://www.bing.com/local/default.aspx?what=" + name + "&where=" + location); var htmlDoc = new HtmlAgilityPack.HtmlDocument(); htmlDoc.OptionFixNestedTags = true ; htmlDoc.LoadHtml(html); var nodes = htmlDoc.DocumentNode.SelectNodes( "//div[@class='ecEnclosure']" ); if (nodes != null ) { foreach (HtmlNode node in nodes) { var bName = node.Descendants( "a" ) .Where(s => s.GetAttributeValue( "class" , "" ).Contains( "ecHeaderLink" )) .Select(s => s.InnerText).FirstOrDefault(); var address = node.Descendants( "span" ) .Where(s => s.GetAttributeValue( "id" , "" ).Contains( "AddressLine" )) .Select(s => s.InnerText).FirstOrDefault(); var phone = node.Descendants( "span" ) .Where(s => s.GetAttributeValue( "class" , "" ).Contains( "ecAddress" )) .Select(s => s.InnerText).FirstOrDefault(); var website = string .Empty; var links = node.Descendants( "a" ) .Where(s => s.GetAttributeValue( "id" , "" ).Contains( "ohlWeb" )) .Select(s => s).FirstOrDefault(); if (links != null ) website = links.GetAttributeValue( "href" , "" ); if (! string .IsNullOrEmpty(bName)) { var bCard = new Business() { Address = address ?? string .Empty, Name = bName ?? string .Empty, PhoneNumber = phone ?? string .Empty, Website = website ?? string .Empty }; //do something with bCard } } } |
Weather information from Accuweather
Example page: http://www.clipthetrip.com/city/london
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 | public class Weather { public string city; public int curr_temp; public string curr_text; public int curr_icon; public List<Forecast> forecast = new List<Forecast>(); } public class Forecast { public string day_date; public string day_text; public int day_icon; public int day_htemp; public int day_ltemp; } //code Weather _weather; if (_weather == null ) { _weather = new Weather(); string _location = code; string _metric = "0" ; string _url = string .Format( "http://wwwa.accuweather.com/adcbin/forecastfox/weather_data.asp?location={0}&metric={1}" , _location, _metric); string _xml = Utils.DownloadWebPage(_url); var _xmlDocument = new XmlDocument(); _xmlDocument.LoadXml(_xml); var _mgr = new XmlNamespaceManager(_xmlDocument.NameTable); _mgr.AddNamespace( "pf" , _xmlDocument.DocumentElement.NamespaceURI); _weather.city =_xmlDocument.SelectSingleNode( "/pf:adc_database/pf:local/pf:city" , _mgr).InnerText; _weather.curr_temp = Convert.ToInt32(_xmlDocument.SelectSingleNode( "/pf:adc_database/pf:currentconditions/pf:temperature" , _mgr).InnerText); _weather.curr_text = _xmlDocument.SelectSingleNode( "/pf:adc_database/pf:currentconditions/pf:weathertext" , _mgr).InnerText; _weather.curr_icon = Convert.ToInt32(_xmlDocument.SelectSingleNode( "/pf:adc_database/pf:currentconditions/pf:weathericon" , _mgr).InnerText); var _xmlNodeList = _xmlDocument.SelectNodes( "/pf:adc_database/pf:forecast/pf:day" , _mgr); int _day = _xmlNodeList.Count; int i = 0; foreach (var _dayItem in _xmlNodeList) { var _forecast = new Forecast(); _forecast.day_date = _dayItem[ "obsdate" ].InnerXml; _forecast.day_text = _dayItem.SelectSingleNode( "pf:daytime" , _mgr)[ "txtshort" ].InnerXml; _forecast.day_icon = Convert.ToInt32(_dayItem.SelectSingleNode( "pf:daytime" , _mgr)[ "weathericon" ].InnerXml); _forecast.day_htemp = Convert.ToInt32(_dayItem.SelectSingleNode( "pf:daytime" , _mgr)[ "hightemperature" ].InnerXml); _forecast.day_ltemp = Convert.ToInt32(_dayItem.SelectSingleNode( "pf:daytime" , _mgr)[ "lowtemperature" ].InnerXml); _weather.forecast.Add(_forecast); i++; // 5 day forecast if (i == 5) break ; } } |
Image Resizing using SimpleDotImage
1 2 3 4 5 6 7 8 9 10 | using (var _imgProcessing = new ImageProcessing()) { using (var _waterMarkedImage = _imgProcessing.Process( imagePath: file, resize: 164 )) { ImageHelper.SaveStream(_waterMarkedImage, thumbFile); } } |
Javascript and CSS bundling using Web.Optimization
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 | using System.Web.Optimization; namespace ClipTheTripWeb { public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { var homeBundleJs = new Bundle( "~/content/js/home" , new JsMinify()); homeBundleJs.Include ( "~/Content/Js/jquery.fullscreenr.js" , "~/Content/Js/jquery.autoSuggest.js" , "~/Content/Js/home.js" ); var homeBundleCss = new Bundle( "~/content/css/home" , new CssMinify()); homeBundleCss.Include ( "~/Content/Css/Site.css" , "~/Content/Css/autoSuggest.css" , "~/Content/Css/tiles.css" ); . . . bundles.Add(homeBundleCss); bundles.Add(homeBundleJs); } } } //Global.ascx protected void Application_Start() { AreaRegistration.RegisterAllAreas(); BundleConfig.RegisterBundles(BundleTable.Bundles); . . } |
<< Home