使用 AJAX 和 ASP.NET 将外部数据源与 MS SQL Server 数据库结合以创建 Google Maps






4.09/5 (8投票s)
2006年5月9日
5分钟阅读

91687

1241
通过 AJAX 和 ASP.NET 环境,将来自外部 Web 服务或 API 的数据与内部 MS SQL 数据库中的数据动态结合,生成 Google 地图。
引言
为了创建一个动态且交互式的 Google 地图应用程序,我们经常需要从互联网或 Web 服务检索一些数据,并将其与我们的内部数据相结合。下面是一个很好的例子,它展示了如何在 AJAX(Asynchronous JavaScript and XML)和 ASP.NET C# 环境中使用一个可重用的类来完成这些任务。该类从互联网检索国家首都列表和美国州中心位置,通过调用 Yahoo! Map 地理编码 Web 服务解析地理编码,并将其与内部 MS SQL Server 数据库(在本演示中为 Northwind)中的数据结合,从而创建 Google 地图。
背景
AJAX 是一项对营销人员友好的新技术,它可以在用户不离开主页的情况下显示更多背景信息。它代表 Asynchronous JavaScript and XML,在这里用于从源页面检索组合数据并将其显示在 Google 地图上。第一种情况是显示不同国家客户的数量;第二种情况是显示不同美国州客户的数量。在我们的网站上,我们统计了来自不同国家和美国各州的校友数量。唯一的区别是,对于世界地图,气泡或信息窗口位于每个首都,而在第二种情况下,信息窗口位于每个州的中心。如果您是第一次阅读,气泡只是 Google 地图上的一个图标,位于精确的经纬度上,用户点击后会弹出一个显示更详细信息的小窗口。
在世界地图视图的第一种场景中,我们查询数据库并检索国家名称和首都列表,构造一个 URL 来查询 Yahoo! 地图地理编码免费服务以获取精确的地理编码,并创建一个包含每个国家客户数量的新 XML 文件。在第二个美国各州的场景中,我们首先查询数据库并获取每个州内的客户数量,然后从 toeat.com 提供的 Web 服务中检索地理中心位置,并创建一个包含地理编码和每个州客户数量的新 XML 文件。
最后,所有数据都使用 GXmlHttp
显示在 Google 地图上。
类内部结构
我有一个名为 MapDataAccess.cs 的类,用于查询 Northwind 数据库并以 SqlDataReader
的形式返回客户数量。以下是用于在数据库中进行计数和分组的三种方法之一。
public SqlDataReader GetStateStat(string strCountry)
{
string queryString="SELECT COUNT(*) AS StateTotal, Region" +
" FROM Customers where COUNTRY = '" +
strCountry + "' GROUP BY Region";
return SqlHelper.ExecuteReader(conn,
CommandType.Text, queryString);
}
第二个类名为 MapData.cs,它调用 Yahoo! 地图地理编码服务来解析经纬度。该方法根据不同的国家名称和城市名称以及所需的 Yahoo! 地图服务密钥构造适当的 URL 字符串。
public void SetGeocodesEach(string strCountry, string strCity){
try
{
if (strCountry == "USA")
{
string url = "http://api.local.yahoo.com/MapsService" +
"/V1/geocode?appid=" + Global.GMYahooKey +
"&city= "+strCity+
"&state=Maryland&country=" +
strCountry;
XmlTextReader xreader;
xreader = new XmlTextReader(url);
DataSet ds = new DataSet();
ds.ReadXml(xreader);
lat = Convert.ToDouble(ds.Tables[0].Rows[0]["Latitude"]);
lng = Convert.ToDouble(ds.Tables[0].Rows[0]["Longitude"]);
}
else
{
string url = "http://api.local.yahoo.com/MapsService" +
"/V1/geocode?appid=" + Global.GMYahooKey +
"&city= " + strCity +
"&state=&Country=" + strCountry;
XmlTextReader xreader;
xreader = new XmlTextReader(url);
DataSet ds = new DataSet();
ds.ReadXml(xreader);
lat = Convert.ToDouble(ds.Tables[0].Rows[0]["Latitude"]);
lng = Convert.ToDouble(ds.Tables[0].Rows[0]["Longitude"]);
}
}
catch (Exception e)
{
//The next line of code is for debugging purpose.
//HttpContext.Current.Response.Write(
// string.Format("<P>{0}: {1}</P>",
// e.Message, strAddr));
return;
}
}
第三个类名为 GoogleAddress.cs,它通过提供地址信息来存储从外部 Web 服务接收到的经度和纬度。
合并并输出 XML 的 ASPX 页面
StateData.aspx 页面可以单独调用,以检查数据错误或连接错误。要写入 XML 文件,可以使用 XmlTextWriter
,并将其内容类型设置为 text/xml。
Response.Clear();
Response.ContentType = "text/xml";
XmlTextWriter objX = new XmlTextWriter(Response.OutputStream,
System.Text.Encoding.UTF8);
系统首先从 toeat.com 加载外部源作为 XmlDocument
,用于州中心地理编码。
XmlDocument nodes = new XmlDocument();
nodes.Load("http://www.toeat.com/Map/US/");
然后,它将美国的每个州中心地理编码与数据库计数结果合并,通过应用 XPath 来定位确切节点,从而在不进行额外循环的情况下提高性能。
XmlNode node =
doc.SelectSingleNode("descendant::marker[@title='" +
strLState + "']");
之后,它会写入一个包含标记、纬度、经度、国家、标题和消息属性的 XML 文件,这些属性是 Google 地图所必需的。
objX.WriteStartElement("marker");
objX.WriteAttributeString("lat", node.Attributes["lat"].InnerXml);
objX.WriteAttributeString("lng",node.Attributes["lng"].InnerXml);
objX.WriteAttributeString("country",strCountry);
objX.WriteAttributeString("title", strSState);
objX.WriteAttributeString("message", dr["StateTotal"].ToString());
objX.WriteEndElement();
要合并首都国家的中心地理编码与数据库结果,我们需要首先渲染每个国家首都的地理编码,然后编写一个包含数据库数据的 XML 文件。以下是用于解析地理编码的代码片段。
MapData md = new MapData();
md.SetGeocodesEach(strC, MapData.Capital(strC).Trim());
md.GetGeocodes(ga);
AJAX 在行动,展示 Google 地图
神奇的页面名为 AlumStatesMap.aspx,其代码隐藏页面为世界视图和美国视图设置了默认中心位置的地理编码。为了让所有气泡都适合一个地图,我为世界视图随机选择了利比亚周围的中心点,为美国视图选择了堪萨斯州的中心点。它还获取 Google 地图密钥和显示尺寸。此页面上放置了一个单选按钮,用于在世界视图和美国视图之间切换,这也会设置国家会话变量、显示尺寸和中心地理编码的默认值。
准备带有图标和信息窗口的地图
var icon = new GIcon();
icon.image="http://labs.google.com/ridefinder/images/mm_20_red.png";
icon.shadow="http://labs.google.com/ridefinder/images/mm_20_shadow.png";
icon.iconSize = new GSize(12, 20);
icon.shadowSize = new GSize(22, 20);
icon.iconAnchor = new GPoint(6, 20);
icon.infoWindowAnchor = new GPoint(5, 1);
通过从代码隐藏页面填充地理编码来居中地图。
var map = new GMap(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.centerAndZoom(new GPoint(<%Response.Write(longitude);%>
创建一个标记,当用户点击它时,其信息窗口会显示州或国家名称以及该地区的客户数量。
function createMarker(point, infostring) {
var marker = new GMarker(point, icon);
GEvent.addListener(marker, 'click', function() {
marker.openInfoWindowHtml(infostring);
});
return marker;
}
从 StateData.aspx 页面下载数据,并将其加载到地图上。数据是通过查询数据库并将其组织成 XML 格式以方便上传来动态生成的。
var request = GXmlHttp.create();
var page;
page = "StateData.aspx";
var url = page +"?RandomKey=" +
Math.random() * Date.parse(new Date());
request.open('GET', url, true);
request.onreadystatechange = function() {
if (request.readyState == 4) {
var xmlDoc = request.responseXML;
var markers =
xmlDoc.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
var point = new
GPoint(parseFloat(markers[i].getAttribute("lng")),
parseFloat(markers[i].getAttribute("lat")));
var info = markers[i].getAttribute("title") + "<br>";
info += "Number of Customers: " +
markers[i].getAttribute("message");
var marker = new createMarker(point, info);
map.addOverlay(marker);
}
}
兴趣点
要将 aspx 页面的输出转换为 XML 格式,请使用以下代码片段。
Response.ContentType = "text/xml";
为了提高性能并减少不必要的循环,使用了 XPath。
XmlNode node =
doc.SelectSingleNode("descendant::marker[@title='" +
strLState + "']");
要将变量从代码隐藏页面传递到 HTML 页面,请使用 Response
对象。
map.centerAndZoom(new GPoint(<%Response.Write(longitude);%>,
<% Response.Write(latitude);%>), <%Response.Write(displaySize);%>);
要检索 XML 数据中的新数据,每次调用页面时提供一个随机页面密钥,或者不保留缓存版本。
var url = page +"?RandomKey=" + Math.random() * Date.parse(new Date());
要在 FireFox 浏览器中包装信息窗口的文本,请使用 div
标签。
var info = markers[i].getAttribute("title") + " ";
info += "Number of Customers: " +
markers[i].getAttribute("message");
最终注释
由于我在论文中使用了 Response
、div
和 br
等关键词,此页面的代码可能无法正常工作。请参考 Zip 文件中的参考代码。此 Web 演示项目与生产代码之间也存在差异,请访问我的 博客,或查看在线的 KD 校友统计 Google 地图。