Archive

Posts Tagged ‘.NET’

Building database and web service driven asynchronous google map application

May 22nd, 2007

Map API could help build very cool mashup websites.  Often times a back end database is the source of the objects to be drawn on the map and querying for those objects from the database based on the parameters the users choose on the website (e.g., state, city, search criteria) gets complex.  Also to improve the user experience, asynchronous map loading is desired so that while the next batch of objects is being retrieved from the server, the current ones on the map could continue functioning.  To address all these challenges and build a smooth database driven asynchronous loading map application, web service can serve as the bridge between the server side complex data model and the client side map drawing logic.  The following describes the steps of implementing such architecture and a sample code project created in Visual Studio (free version could be downloaded here).  This time, I played with Google Maps API.

ws_map.jpg

Firstly, set up a basic ASP.NET AJAX-enabled web site through the Visual Studio wizard.  You may need to download the AJAX extension from http://ajax.asp.net/.  Inside Default.aspx, add a div in the body like the following to host the map

<div id="map" style="width: 90%; height: 600px; margin-left:auto; margin-right:auto"></div>

Reference the google api javascript source and your own javascript file (e.g., gmap.js where the client side mapping code is located) in the head section.

Next is to prepare the data on the server side.  It is actually much easier to set up a relational database in Visual Studio by a just few clicks and there are tons of such examples on the web.  So here let’s try a slightly trickier scenario where we only have a static plain text CSV data file (e.g., exported from an legacy system or Excel spreadsheet) that contains various cities and the fun places in them to be drawn on the map.  Add that data file (e.g., mapdata.csv) under the App_Data/ folder in the solution explore.  Assume the data file has 3 columns State, City, and FunPlace.  Now create a web service (e.g., MapDataWebService) to extract the data from the CSV file and serve to the client side mapping code.  To add this web service, right click the project in the solution explore, select "Add New Item…", select "Web Service", and then rename the file name into "MapDataWebService.asmx".  The web service skeleton is automatically added under App_Code/.  Open it and add 2 web methods getAllStates() and getFunPlacesByState(string state).  The former is used to populate the dropdown on the web page to select a state and the latter is to get the fun places of the selected state.  Both methods connect to the data file through OLE DB and query the data using convenient SQL syntax.  To quickly unit test the web method, you could open MapDataWebService.asmx and press F5 to run the web service alone.

The return value of getFunPlacesByState(string state) would be an array of objects (type of class Place), each of which contains the latitude and longitude of the city and the name of the fun place in that city.  The class Place is the object oriented representation of this information.  The web service will return the objects to the JavaScript caller.  In order for the caller to get the consistent objects and dereference them the same way as in C#, the following directive should be added to the top of the web service code and a reference to the assembly System.Web.Extensions.dll needs to be added to the solution too.  If you don’t have this assembly already installed on your machine, you could download and install "ASP.NET Ajax" from http://ajax.asp.net/.


using System.Web.Script.Services;

    [ScriptService]
    [GenerateScriptType(typeof(Place))]
    public class MapDataWebService : System.Web.Services.WebService
    {
….
    }
    public class Place
    {
….
    }

After the data service is created, the getAllStates() web method could be used to build a data source to populate the dropdown list.  Drag and drop a dropdown list onto the Default.aspx, select to create a new data source from its context menu, choose object as the type, MapDataWebService as the business object, and getAllStates() as the SELECT method.  The data binding is automatically done.  Add an onchange event handler to this control to trigger the mapping function (e.g., drawMarkers) and we are almost done.

The last step is to implement the mapping method drawMarkers() in gmap.js.  It retrieves the state that the user chose in the dropdown and use it as the parameter to call the web service method getFunPlacesByState(state) asynchronously.  The callback function will receive the resulting list of Place objects and then use the Google maps API to draw them on the map.  To successfully make the web service call from JavaScript, it has to be registered in the Default.aspx like the following.

<asp:ScriptManager ID="ScriptManager1" runat="server">
    <Services>
        <asp:ServiceReference Path="~/MapDataWebService.asmx" />
    </Services>
</asp:ScriptManager>

To make it more fun and improve the user experience, during the async web service call, a spinning progress icon could be display indicating that the data is being loaded.  Overall, no whole page loading is done and web page looks better.  If you are interested the sample solution and code can be downloaded GMapExample.zip.  Before you can compile and run this web site, go to http://www.google.com/apis/maps/ to register your API key and replace the place holder "YOUR_API_KEY" in file Default.aspx and App_Code/MapDataWebService.cs.

By the way, a comment about Google Maps API.  The markers manager is a convenient way of aggregating all the markers, but removing objects from the manager seems buggy.  Whenever the map zoom level is changed, all the removed markers come back on the map.  The markers in the manager are not controlled by the map.removeOverlay() either.  Other than that, the API works pretty well.

Sample code download: GMapExample.zip

Web , , , , , , , , , ,

Difference in Paradigm: Open Source .vs. Microsoft

April 28th, 2007

One can enumerate hundreds of difference between software from open source community and companies like Microsoft.  There are fundamental things that cause the difference – the paradigm of programming, the architecture of software family, and development productivity, etc.

On the server side development platform for example, popular open source tools are the well known LAMP.  Four pieces are done by totally different groups of people, on different time schedule, and with different design style.  They are all good products without doubt.  They work together very well for sure too.  Coding something on LAMP feels super geeky, because you control everything from top to the bottom.  Commercial software makers like Microsoft have some different considerations.  For good manageability, installation, configuration, migration, and so on mostly have easy to use (at least try to) GUI.  For productivity, many of the routines are abstracted and hidden away from the application developers.  For example, in ASP.NET, post backs, event handler registration, page templating and all those kind of wiring work is hidden.  Writing server side code feels more straight forward like writing desktop application.  ASP.NET really evolves from a programming language up to a server side framework.  With the Visual Studio .NET’s help like IntelliSense, debug tracing on both server and client side, visualized server control customization with sample data, and so on, developers are more free to focus on the business logic of the software, which is critical for business.

Talking about the hot AJAX.  Interestingly this technology was started by Microsoft when building the outlook web access.  Because it is majorly for business rather than the consumers on the Internet, it didn’t surface that much until Google Suggest and Maps made the splash with it.  To code in AJAX there are a lot of plumbing work underneath to wire up the connections between the client side scripts and the server side handler, AJAX for ASP.NET wraps all these up and provide a few straight forward abstract controls to improve the productivity of the application developers.

There are debates in many companies and organizations about Wiki and SharePoint too.  Again like the comparison between PHP and ASP.NET, SharePoint is more of a platform that contains Wiki features and many other capabilities.  Wiki starts out to do collaborative web content editing, while SharePoint is designed to be the collaboration platform which integrates with Office suites, workflow, enterprise search engine, content management, SharePoint Designer (visual design tool), etc.

Open source software products are simple, developer-enjoyable, and inexpensive upfront.  Commercial products are more business friendly, enterprise infrastructure oriented, productiviey oriented (sometimes productivity and developer-enjoyable are not well aligned :) ), and more expensive upfront.  They have much difference in the fundamental design paradigm.  Comparing the two different types of products really depends on the specific requirements rather than a religious belief.

Tech , , , , , ,

Extract Favorite Websites Collection from Bookmark RSS feeds

February 25th, 2007

Bookmarking a website and bookmarking an article are different usage of the bookmarking tools. You may want to have a clean collection of all your favorite websites and on the other hand you may want to bookmark multiple good articles from the same website. This way your bookmark collection is a mixture of both. This is my little frustration of using sites like http://del.icio.us/. It’s great in collect articles and links, but not so great to keep a clean list of my favorite websites. Although I can use a different bookmarking tool (e.g., http://favorites.live.com/, which could sync with IE bookmarks) to collect just sites, it’d be nice if I could keep them in one place. So I developed a custom web control that could be put on your website to display all the websites of a list of http://del.icio.us/ RSS feeds in the order of popularity. Multiple articles of each websites are collapsed into one entry shown for that website, and the number of the articles bookmarked from that site is used as the indicator of the popularity of that site within the RSS feeds. So the more articles of a website that are bookmarked, the more popular the website is. In my example of using this web control, I put my bookmark feeds and the del.icios.us homepage hotlist feeds in so that I will get a list of all the websites either I bookmarked or on the hostlist.

<cc1:BookmarkedWebsites
    id
="WebCustomControl1_1"
    Url
="http://del.icio.us/rss/dbtu/; http://del.icio.us/rss/"
    runat
="server"></cc1:BookmarkedWebsites>

The "Url" property of the control specifies a list of RSS feeds to extract from. The delimiter is ";".

RSS.NET library is used to parse the RSS feed. The website part (domain) of the URL is extracted and used as the collapsing key.

protected override void RenderContents(HtmlTextWriter output)
{
    // Get each individual RSS feed
    char
[] delimiters = { ‘;’ };
    string[] feeds = Url.Split(delimiters);
   
    // Get all websites
    SortedDictionary
<string, int> sites =
        new
SortedDictionary<string, int>();
    foreach (string feedUrl in feeds)
    {
        RssFeed feed = RssFeed.Read(feedUrl);
        foreach (RssChannel channel in feed.Channels)
        {
            foreach (RssItem item in channel.Items)
            {
                string link = item.Link.Scheme + "://" +
                    item.Link.Host;
                if (sites.ContainsKey(link))
                {
                    sites[link]++;
                }
                else
                {
                    sites[link] = 1;
                }
            }
        }
    }

    // Reorder it on the number of occurrence (thus popularity)
    KeyValuePair
<string, int>[] popSites =
        new
KeyValuePair<string,int>[sites.Count];
    sites.CopyTo(popSites, 0);
    Array.Sort(popSites, new SitePopularityComparer());
    foreach (KeyValuePair<string, int> s in popSites)
    {
        output.Write("( " + s.Value + " ) <a href=\"" +
            s.Key + "\">"+ s.Key + "</a><br />");
    }
}

public class SitePopularityComparer : IComparer
{
    int IComparer.Compare(object x, object y)
    {
        return ((KeyValuePair<string, int>)y).Value -
                ((KeyValuePair<string, int>)x).Value;
    }
}

The web control looks like the following:

 

Furthermore, it would be cooler to be able to sync this website list into the browser bookmark so that you can use them as your reading list even more conveniently.

The prototype source code can be downloaded here: MyFavoriteWebSites.zip.

.NET , , , ,