Tag Archives: AGS Web App

ESRI Silverlight Application Plus(chs)

演示地址:http://newnaw.com/pub/sl/esrislappplus 其中一些布局感谢”金属狂人”的建议
版本:ArcGIS API for Silverlight 1.2
说明:安装好ArcGIS API for Silverlight 1.2后,在vs2008中会出现两个模板程序:ESRI Standard Map Application和ESRI Showcase Map Application。其中前者与广为流传的Flex Viewer很像,但界面过于简陋,功能过于简单,如果想以它为基础构建快速应用的话还得费点功夫。在它的基础上,我将Code Gallery中的一些功能添加了进来,并将界面基本汉化,下面放出程序代码供大家学习交流之用。
功能:放大/缩小,前/后视图,放大镜,缩略图,书签,Identify,图层属性表,3个测量功能,地址定位。
截图:

下载地址:http://bbs.esrichina-bj.cn/ESRI/thread-64924-1-1.html

ps:地址搜索用到了Google Map API,具体应用时请注意版权问题。
pps:这个程序仅是个人集成,属于民间作品。
ppps:这两天之内ArcGIS API for Silverlight 2.0 beta版本便会放出,但要充分利用新的功能,必须拥有ArcGIS Server 10才行。所以对于暂时升级不了AGS的朋友,这个东西应该还是凑合能用一段时间的。

ArcGIS API for Silverlight中专题地图的实现浅析

        专题地图是突出表现特定主题或者属性的地图。常见专题地图类型有唯一值渲染,分类渲染,柱状图,饼状图,点密度图等。这些在ArcMap里,图层属性的Symbology标签中已有很好的诠释。
        三种客户端API中目前为我们提供了现成的UniqueValueRenderer和ClassBreakRenderer功能,但有些食之无味,弃之可 惜。原因有二:1、领导常常并不认可这两种简约而不简单的专题图,因为他们没有看到复杂的圆饼和长柱;2、API中提供的两种专题图利用 GraphicsLayer自己实现也比较简单。这次以Silverlight API为例,探讨一下传统专题图实现的可能性。
        要呈现专题图,有两个步骤:
        1、绘制chart,比如饼图和柱图。有以下完成途径:Google Chart APISilverlight Toolkit中的Chart功能(开源)Visifire(开源)。前者使用最简单,后者效果最好,暂时抛弃中庸的。
        2、将绘制好的图形显示出来。因为是与地图服务无关的数据,所以可用GraphicsLayer来完成,而且可以利用其中的Cluster功能,推荐使用此办法。此时需要将chart定制为Graphic的Symbol;也可以利用ElementLayer来显示,此时需要将chart定制为UIElement。
        通过三个例子来说明,专题要素是我国人口总数、城市人口数、非城市人口数。
        1、选用GraphicsLayer,利用cluster功能,通过google api绘制静态chart。大概步骤:通过继承GraphicsCluster基类实现cluster功能,通过形如:http://chart.apis.google.com/chart?chs=100×100&chd=t:60,40&cht=p3的请求利用google chart tools绘制chart,通过PictureMarkerSymbol承载chart,交给Graphic显示。效果如图:

        补充说明:1、通过google chart创建的静态图形没办法“说话”,不过可以利用GraphicsLayer的Maptip来实现简单交互;2、google chart目前还没办法创建背景透明的chart,Silverlight目前也不能去除位图背景色,但可以通过服务器上的GDI+功能来使背景透明,然后显示。
        2、选用GraphicsLayer,利用cluster功能,通过visifire绘制可交互的chart。大概步骤:通过继承 GraphicsCluster基类实现cluster功能,通过继承MarkerSymbol来允许visifire产生的chart作为Symbol 赋给Graphic,最后显示Graphic。效果如图:

        补充说明:visifire目前暂不支持databinding,所以利用改变MarkerSymbol的ControlTemplate办法无法动态修改chart数据。
        3、选用ElementLayer,通过visifire绘制可交互的chart。大概步骤:根据专题要素动态创建可交互的chart,利用Graphic的Geometry来定位。效果如图:

        补充说明:可根据比例尺处理chart的详细程度,比如小比例尺时尽量精简chart,避免互相压盖,大比例尺时显示详细的chart信息;必要时可自己实现cluster算法。

ArcGIS中的线性参考/动态分段技术(三)几个Linear Referencing应用场景在AGS中的实现

        现在来实现上面提到的3个功能。
1、对于某条公路上的一点进行Identify操作,要求返回该点在公路上的桩号值:
        以Silverlight API为例。为了在服务器端使用ArcObjects,在Asp.net工程中添加一个名为LinearRef的Silverlight-Enabled WCF Service,在LinearRef.svc.cs文件中添加以下代码:

namespace RoadDycSeg.Web.WCF
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class LinearRef
{
public IRouteLocator2 pRtLocator = null;
ESRI.ArcGIS.Server.IServerObjectManager pSOM = null;
public ESRI.ArcGIS.Server.IServerContext pServerContext = null;

public LinearRef()
{
ESRI.ArcGIS.ADF.Identity identity = new ESRI.ArcGIS.ADF.Identity("ArcGISWebServices", "yourpassword", "");
ESRI.ArcGIS.ADF.Connection.AGS.AGSServerConnection agsconn = new ESRI.ArcGIS.ADF.Connection.AGS.AGSServerConnection("localhost", identity);
agsconn.Connect();
pSOM = agsconn.ServerObjectManager;
pServerContext = pSOM.CreateServerContext("shaanxi", "MapServer");
ESRI.ArcGIS.Carto.IMapServer2 pMapServer = pServerContext.ServerObject as ESRI.ArcGIS.Carto.IMapServer2;
ESRI.ArcGIS.Carto.IMapServerObjects2 pMapServerObjects = pMapServer as ESRI.ArcGIS.Carto.IMapServerObjects2;
ESRI.ArcGIS.Carto.IMap pMap = pMapServerObjects.get_Map(pMapServer.DefaultMapName);
IFeatureClass pFC = (pMap.get_Layer(2) as ESRI.ArcGIS.Carto.IFeatureLayer).FeatureClass;

//create the RouteLocator
IDataset dS = (IDataset)pFC; // A polylineM feature class.
IName name = dS.FullName;
IRouteLocatorName rtLocatorName = pServerContext.CreateObject("esriLocation.RouteMeasureLocatorName") as IRouteLocatorName;
rtLocatorName.RouteFeatureClassName = name;
rtLocatorName.RouteIDFieldName = "道路编码";
rtLocatorName.RouteMeasureUnit = esriUnits.esriUnknownUnits;
name = (IName)rtLocatorName;
pRtLocator = (IRouteLocator2)name.Open();

pServerContext.ReleaseContext();
}

// Add more operations here and mark them with [OperationContract]

[OperationContract]
///

/// used by the client Identify operation and return the result
///

/// the x coords of the mouseclick in map units /// the y coords of the mouseclick in map units /// the map distance of 1 pixel /// a identifyresult class defined in Classes.cs. If no result, mvalue=x=y=-1
public IdentifyResult Identify(double mapX, double mapY, double resolution)
{
pServerContext = pSOM.CreateServerContext("shaanxi", "MapServer");

IdentifyResult ir = new IdentifyResult("", -1, -1, -1);

IPoint pPoint = pServerContext.CreateObject("esriGeometry.Point") as IPoint;
pPoint.PutCoords(mapX, mapY);
IEnvelope pEnvelope = pPoint.Envelope;
pEnvelope.Expand(10 * resolution, 10 * resolution, false);

IEnumRouteIdentifyResult pEnumResult = pRtLocator.Identify(pEnvelope, "");
pEnumResult.Reset();
//only get the first result
if (pEnumResult.Count > 0)
{
IRouteLocation pRL = null;
IFeature pF = null;
pEnumResult.Next(out pRL, out pF);
IRouteMeasurePointLocation pRMPL = pRL as IRouteMeasurePointLocation;

//retrieve the location geometry by calling LOCATE method
IRouteLocation routeLocation = pServerContext.CreateObject("esriLocation.RouteMeasurePointLocation") as IRouteLocation;
routeLocation.MeasureUnit = esriUnits.esriUnknownUnits;
routeLocation.RouteID = pRL.RouteID;
routeLocation.LateralOffset = 0;
IRouteMeasurePointLocation rMPointLoc = (IRouteMeasurePointLocation)routeLocation;
rMPointLoc.Measure = pRMPL.Measure;

IGeometry geom;
esriLocatingError locError;
pRtLocator.Locate((IRouteLocation)rMPointLoc, out geom, out locError);

ir.RouteID = pRL.RouteID.ToString();
ir.MValue = pRMPL.Measure;
ir.X = (geom as IPointCollection5).get_Point(0).X;
ir.Y = (geom as IPointCollection5).get_Point(0).Y;
}

pServerContext.ReleaseContext();

return ir;
}

        其中,IdentifyResult是自定义的一个类,用来存储查询的结果:
namespace RoadDycSeg.Web.WCF
{
///

/// the result of Identify operation
///

[DataContract]
public class IdentifyResult
{
[DataMember]
public string RouteID {get;set;}
[DataMember]
public double MValue {get;set;}
[DataMember]
public double X {get;set;}
[DataMember]
public double Y {get;set;}

public IdentifyResult(string routeid, double mvalue, double x, double y)
{
RouteID = routeid;
MValue = mvalue;
X = x;
Y = y;
}
}
}

        Identify方法需要传入3个参数,一个点的地理坐标以及当前地图的Resolution,后者用来生成一个10像素的缓冲区,方便用户的点击操作;其中利用IRouteLocator2.Identify方法获得M值,据此利用 IRouteLocator2.Locate方法获得精确落在公路上的点的Geometry,用以显示在客户端;如果用户点击的点距离公路较远,则IRouteLocator2.Identify结果为空,返回的IdentifyResult中M值为-1。
        在Silverlight工程中,Add Service Reference,找到刚才的LinearRef服务,取名为LRService。
        客户端中,新建一个COperation类,实现业务操作。
public class COperation
{
private LRService.LinearRefClient LR = null;
private GraphicsLayer glayer = null;
private bool isBusy = false;//indicate whether there is an operation is performing
private Map Map1 = null;
public COperation(Map map)
{
Map1=map;
glayer = Map1.Layers["glayer"] as GraphicsLayer;
//initialize the LR object
LR = new RoadDycSeg.LRService.LinearRefClient();
LR.IdentifyCompleted += new EventHandler(LR_IdentifyCompleted);
}
private void LR_IdentifyCompleted(object sender, LRService.IdentifyCompletedEventArgs e)
{
LRService.IdentifyResult ir = e.Result;
//add a point graphic to the map with attributes displaying by the maptip, maptip defined in mainpage.xaml
if (ir.X > 0)//the result exists
{
> Graphic g = new Graphic()
{
Geometry = new MapPoint(ir.X, ir.Y),
Symbol = Application.Current.Resources["strobeSymbol"] as Symbol,
};
g.Attributes.Add("RouteID", ir.RouteID);
g.Attributes.Add("桩号", ir.MValue);
g.Attributes.Add("X坐标", ir.X);
g.Attributes.Add("Y坐标", ir.Y);
glayer.Graphics.Clear();
glayer.Graphics.Add(g);
}
isBusy = false;
}

private void Map1_Identify(object sender, ESRI.ArcGIS.Client.Map.MouseEventArgs e)
{
if (!isBusy)
{
LR.IdentifyAsync(e.MapPoint.X, e.MapPoint.Y, Map1.Resolution);
isBusy = true;
}
}

        在需要使用Identify功能时,将Map控件的Click事件绑定到Map1_Identify即可。结果如图:

2、输入起始和终止桩号,要求将其间的路段显示在地图上:
        要解决这个问题,关键是根据两个M值,求的其间一段公路的Geometry。利用的仍然是IRouteLocator2.Locate方法,其中的第一个参数routeLocation,传入的是用IRouteMeasureLineLocation接口定义的“线性位置”,具体可参考帮助文档。
        仍然是在LinearRef.svc.cs文件的LinearRef类中,添加以下方法:
[OperationContract(Name = "RetrieveRoutePortionGeometry")]
///

/// used by the client,such as QueryPortion operation, to retrieve the geometry of the route portion
///

/// the route id which the portion is part of /// fromMvalue /// toMvalue /// a json string with specific format,such as [{"x":1111,"y":1111},{"x":2222,"y":2222},{"x":3333,"y":3333}.....]
public string RetrieveRoutePortionGeometry(string routeid, double fromMValue, double toMValue)
{
pServerContext = pSOM.CreateServerContext("shaanxi", "MapServer");
IRouteLocation routeLoc = pServerContext.CreateObject("esriLocation.RouteMeasureLineLocation") as IRouteLocation;
routeLoc.MeasureUnit = esriUnits.esriUnknownUnits;
routeLoc.RouteID = routeid;
routeLoc.LateralOffset = 0;
IRouteMeasureLineLocation rMLineLoc = (IRouteMeasureLineLocation)routeLoc;
rMLineLoc.FromMeasure = fromMValue;
rMLineLoc.ToMeasure = toMValue;

IGeometry geom;
esriLocatingError locError;
pRtLocator.Locate((IRouteLocation)rMLineLoc, out geom, out locError);

pServerContext.ReleaseContext();

//return the routeportion's vertices
StringBuilder sb = new StringBuilder("[");
IPolyline pLine = geom as IPolyline;
IPointCollection pPC = pLine as IPointCollection;
//json format such as:
//[{"x":1111,"y":1111},{"x":2222,"y":2222},{"x":3333,"y":3333}.....]
for (int i = 0; i < pPC.PointCount; i++)
{
sb.Append("{"x":");
sb.Append(pPC.get_Point(i).X.ToString());
sb.Append(","y":");
sb.Append(pPC.get_Point(i).Y.ToString());
sb.Append("},");
}
//remove the last ","
sb.Remove(sb.Length - 1, 1);
sb.Append("]");
return sb.ToString();
}


        由于在服务器端的AO操作,产生的结果是ESRI.ArcGIS.Geometry.IGeometry类型,而客户端需要的则是ESRI.ArcGIS.Client.Geometry.Geometry类型,所以需要对结果序列化/反序列化,这里采用JSON字符串处理。客户端处理结果的函数仍然放在COperation.cs文件中,如下:
private void LR_RetrieveRoutePortionGeometryCompleted(object sender,LRService.RetrieveRoutePortionGeometryCompletedEventArgs e)
{
//create a esri.arcgis.client.geometry.polyline from the coords of points contained in the json string
string jsonpoints = e.Result;
JsonArray jsonarrays = (JsonArray)JsonArray.Load(new System.IO.StringReader(jsonpoints));
ESRI.ArcGIS.Client.Geometry.Polyline line = new ESRI.ArcGIS.Client.Geometry.Polyline()
{
SpatialReference = Map1.SpatialReference,
};
ESRI.ArcGIS.Client.Geometry.PointCollection pc = new ESRI.ArcGIS.Client.Geometry.PointCollection();
foreach (JsonObject jo in jsonarrays)
{
pc.Add(new ESRI.ArcGIS.Client.Geometry.MapPoint(jo["x"], jo["y"]));
}
line.Paths.Add(pc);

//add a graphic
Graphic g = new Graphic()
{
Geometry = line,
Symbol = Application.Current.Resources["LineSymbol"] as SimpleLineSymbol,
};
glayer.Graphics.Add(g);
}

        Silverlight中提供了System.Json库,可以非常方便的对JSON字符串进行解析。结果如图:

3、类似GoogleMap的交通流量地图:
        首先看一下Google的交通流量地图:

        可以看出,之所以能产生不同颜色段,需要的数据有3个:该段的起始和终止M值,该段的车流量。假设我们获取的业务数据表(EventTable)如下:

        联想到上面第二个应用场景,我们便想可以获取所有交通数据后,用循环的办法展示出交通流量地图。但这里有两个问题需要思考:1、即使使用IRouteLocator2.LocateRow方法,服务器端根据起止M值解析出所有的分段图形需要一次循环,客户端将这些图形显示出来还需要一次循环,这样是否合理?2、由于结果显示在客户端,不同用户发出请求时,都将重复上面两个循环,如何改进?
        解决问题一:在第二节的Linear Referencing实现原理中,提到了RouteEventSource类,可以将它看作是把Route FeatureClass和EventTable组合在一起的结果,而该类继承自FeatureClass,可当作一个FeatureClass来用。在ArcMap中观察生成后(利用Make Route Event Layer工具)的RouteEventSource层:

        不仅包含了EventTable中的事件,还有了我们想要的Shape字段(可取出Geometry)。其实Shape字段中的内容,是利用Dynamic Segmentation技术动态计算出来的。看其图层属性便知,它是在内存中动态生成的:

        有了FeatureClass,我们便可以对整个图层进行一次渲染,避免服务器端和客户端的两次循环了。这里要注意,FeatureClass是动态生成的,图层便是动态添加,在地图服务的REST接口中无法暴露出来,也就不能利用客户端API的渲染技术了。
        解决问题二:利用SOA的思想,将交通流量图做成一个Traffic服务,不同用户请求时动态添加该服务即可。想想这个服务应该具有的特性:不同时段的交通图,需要动态生成;如果交通图已经生成,则无需重新生成,显示即可。所以我们采取池化方式服务(pooled-service)的特性,刚好解决这一问题。
        这个场景我们用Web ADF来实现(客户端API与前两个场景相同)。
        首先准备两个Map Service:底图服务:shaanxi,交通流量图服务:ShaanxiTraffic。
        后者在ArcMap中打开是这样的:

        ShaanxiTraffic服务除了动态生成的交通流量图外,不需要在显示任何信息,所以发布时是空白的;因为动态生成的RouteEventSource将作为图层插入到这个地图服务中,所以Route FeatureClass必须也在这个mxd中才行。
        Default.aspx页面中放置一个MapResourceManager控件、一个Map控件、一个CallbackButton按钮和一个GridView控件。先看一下结果:

        点击按钮后:

        看一下Default.aspx.cs中按钮的点击事件:
protected void CallbackButton1_Clicked(object sender, EventArgs args)
{
//先判断Traffic服务中是否已经产生结果
if (hasTrafficResult())//Traffic服务中已经有结果
{
//将结果插入地图
InsertTrafficService();
}
else//服务中还没有结果
{
//先生成交通流量结果
MakeResult();
//将结果插入地图
InsertTrafficService();
}
//显示RouteEventSource的属性表
DisplayAttributeTable();
}

        思路都在代码中。依次来看几个函数:
///

/// 判断池化的Traffic服务中,获取的ServerContext是否已经产生结果
///

/// true or false
private bool hasTrafficResult()
{
ESRI.ArcGIS.ADF.Identity identity = new ESRI.ArcGIS.ADF.Identity("ArcGISWebServices", "yourpassword", "");
ESRI.ArcGIS.ADF.Connection.AGS.AGSServerConnection agsconn = new ESRI.ArcGIS.ADF.Connection.AGS.AGSServerConnection("machinename", identity);
agsconn.Connect();
pSOM = agsconn.ServerObjectManager;
ESRI.ArcGIS.Server.IServerContext pServerContext = pSOM.CreateServerContext("ShaanxiTraffic", "MapServer");
ESRI.ArcGIS.Carto.IMapServer2 pMapServer = pServerContext.ServerObject as ESRI.ArcGIS.Carto.IMapServer2;
ESRI.ArcGIS.Carto.IMapServerObjects2 pMapServerObjects = pMapServer as ESRI.ArcGIS.Carto.IMapServerObjects2;
ESRI.ArcGIS.Carto.IMap pMap = pMapServerObjects.get_Map(pMapServer.DefaultMapName);
pServerContext.ReleaseContext();
return pMap.LayerCount == 1 ? false : true;
}

        对于ShaanxiTraffic服务,在获得的Server Object中,查看当前Map的图层数(默认有一个隐藏的Road图层),若为1则还未产生结果。
        下面是动态添加服务的函数,注意要设置背景透明,以便能够看到底图服务:
///

/// 动态添加服务
/// y>
private void InsertTrafficService()
{
if (MapResourceManager1.ResourceItems.Count==1)//若已插入交通流量服务,则不做动作
{
MapResourceItem mapResourceItem = new MapResourceItem();
GISResourceItemDefinition definition = new GISResourceItemDefinition();
mapResourceItem.Name = "Traffic";
definition.ResourceDefinition = "Layers@ShaanxiTraffic";
definition.DataSourceDefinition = "machinename";
definition.DataSourceType = "ArcGIS Server Local";
mapResourceItem.Parent = MapResourceManager1;
mapResourceItem.Definition = definition;
ESRI.ArcGIS.ADF.Web.DisplaySettings displaysettings = new ESRI.ArcGIS.ADF.Web.DisplaySettings();
displaysettings.Transparency = 0.0F;
displaysettings.Visible = true;
ESRI.ArcGIS.ADF.Web.ImageDescriptor imagedescriptor = new ESRI.ArcGIS.ADF.Web.ImageDescriptor();
imagedescriptor.TransparentBackground = true;
imagedescriptor.TransparentColor = System.Drawing.Color.White;
displaysettings.ImageDescriptor = imagedescriptor;
mapResourceItem.DisplaySettings = displaysettings;

MapResourceManager1.ResourceItems.Insert(0, mapResourceItem);
MapResourceManager1.CreateResource(mapResourceItem);

if (Map1.ImageBlendingMode == ImageBlendingMode.WebTier)
{
Map1.Refresh();
}
else
{
Map1.RefreshResource("Traffic");
}

CallbackButton1.CallbackResults.CopyFrom(Map1.CallbackResults);
}
}

        MakeResult函数利用ESRI.ArcGIS.Location库来生成交通流量图。由于Traffic服务是池化服务,当第一个用户请求,生成交通流量图后,该实例(servercontext)会返回服务器上而不被销毁,所以下一个用户再次请求时可以直接显示。如果要实现实时的交通流量图,定时在服务器端重生servercontext,并读取当前时段的EventTable即可。
///

/// 生成交通流量的结果
///

private void MakeResult()
{
ESRI.ArcGIS.Server.IServerContext pServerContextTraffic = pSOM.CreateServerContext("ShaanxiTraffic", "MapServer");
ESRI.ArcGIS.Carto.IMapServer2 pMapServer = pServerContextTraffic.ServerObject as ESRI.ArcGIS.Carto.IMapServer2;
ESRI.ArcGIS.Carto.IMapServerObjects2 pMapServerObjects = pMapServer as ESRI.ArcGIS.Carto.IMapServerObjects2;
ESRI.ArcGIS.Carto.IMap pMap = pMapServerObjects.get_Map(pMapServer.DefaultMapName);
//创建RouteLocator
IFeatureClass pFC = (GetLayerByName("Road",pMap) as IFeatureLayer).FeatureClass;
IDataset dS = (IDataset)pFC; // A polylineM feature class.
IName name = dS.FullName;
IRouteLocatorName rtLocatorName = pServerContextTraffic.CreateObject("esriLocation.RouteMeasureLocatorName") as IRouteLocatorName;
rtLocatorName.RouteFeatureClassName = name;
rtLocatorName.RouteIDFieldName = "道路编码";
rtLocatorName.RouteMeasureUnit = esriUnits.esriUnknownUnits;
name = (IName)rtLocatorName;
IRouteLocator2 pRtLocator = (IRouteLocator2)name.Open();

//创建RouteEventProperties,为RouteEventSource做准备
IRouteEventProperties2 rtProp = pServerContextTraffic.CreateObject("esriLocation.RouteMeasureLineProperties") as IRouteEventProperties2;
rtProp.AddErrorField = true;
rtProp.ErrorFieldName = "LOC_ERROR";
rtProp.EventMeasureUnit = esriUnits.esriUnknownUnits;
rtProp.EventRouteIDFieldName = "RouteID";
IRouteMeasureLineProperties rMLineProp = (IRouteMeasureLineProperties)rtProp;
rMLineProp.FromMeasureFieldName = "FromM";
rMLineProp.ToMeasureFieldName = "ToM";

//创建RouteEventSource
ITable eventTable = (pFC.FeatureDataset.Workspace as IFeatureWorkspace).OpenTable("lineEventsTable");
IDataset ds = (IDataset)eventTable;
IName name2 = ds.FullName;
IRouteEventSourceName rtEvtSrcName = pServerContextTraffic.CreateObject("esriLocation.RouteEventSourceName") as IRouteEventSourceName;
rtEvtSrcName.EventTableName = name2;
rtEvtSrcName.EventProperties = (IRouteEventProperties)rMLineProp;
rtEvtSrcName.RouteLocatorName = rtLocatorName;
name2 = (IName)rtEvtSrcName;
IRouteEventSource rtEvtSrc = (IRouteEventSource)name2.Open();
//转换到FeatureClass
pFC = rtEvtSrc as IFeatureClass;

//将RouteEventSource添加到地图中,并进行唯一值渲染
IUniqueValueRenderer pUVR = pServerContextTraffic.CreateObject("esriCarto.UniqueValueRenderer") as IUniqueValueRenderer;
pUVR.FieldCount = 1;
pUVR.set_Field(0, "Vehicles");
pUVR.UseDefaultSymbol = false;
IFeatureCursor pFeatureCursor = pFC.Search(null, false);
IFeature pFeature = pFeatureCursor.NextFeature();
int ifiledindex = pFC.Fields.FindField("Vehicles");//EventTable中的车流量字段
while (pFeature != null)
{
ISimpleLineSymbol pSymbol = pServerContextTraffic.CreateObject("esriDisplay.SimpleLineSymbol") as ISimpleLineSymbol;
double value = double.Parse(pFeature.get_Value(ifiledindex).ToString());
if (value <= 20)
pSymbol.Color = ESRI.ArcGIS.ADF.Converter.ToRGBColor(pServerContextTraffic, System.Drawing.Color.FromArgb(71, 196, 69)) as IColor;
else if (value > 20 && value <= 50)
pSymbol.Color = ESRI.ArcGIS.ADF.Converter.ToRGBColor(pServerContextTraffic, System.Drawing.Color.FromArgb(255, 255, 0)) as IColor;
else if (value > 50 && value <= 100)
pSymbol.Color = ESRI.ArcGIS.ADF.Converter.ToRGBColor(pServerContextTraffic, System.Drawing.Color.FromArgb(201, 59, 46)) as IColor;
else
pSymbol.Color = ESRI.ArcGIS.ADF.Converter.ToRGBColor(pServerContextTraffic, System.Drawing.Color.FromArgb(250, 52, 17)) as IColor;
pSymbol.Width = 5;
pUVR.AddValue(pFeature.get_Value(ifiledindex).ToString(), "Vehicles", pSymbol as ISymbol);
pFeature = pFeatureCursor.NextFeature();
}
IFeatureLayer pFL = pServerContextTraffic.CreateObject("esriCarto.FeatureLayer") as IFeatureLayer;
pFL.Name = "RouteEventSource";
pFL.FeatureClass = pFC;
(pFL as IGeoFeatureLayer).Renderer = pUVR as IFeatureRenderer;

pMap.AddLayer(pFL as ILayer);//to the 0 index
pMapServerObjects.RefreshServerObjects();
pServerContextTraffic.ReleaseContext();
}

        一点注意,在使用IServerContext接口时要及时进行释放。
        思考一下:如何通过Geoprocessing Service来实现“交通流量图”?

利用免费的地图来解决实际问题

        Google Map的API虽然免费,好用,但终究需要那么一些Javascript基础;ESRI最近推出的Mapping for Everyone使用起来就更简便,内容也更丰富,能够让大家轻松地在自己网页里嵌入一张可互动的地图,比如这样就可以查看美国09年的失业率统计:

        它能够帮助我们做什么呢?这就有个例子,这位老兄正利用一张地图,劝说他的好友卖掉房子,准备搬家呢:)

Local方式连接成功,Internet方式连接失败的原因之一

        以前也看到论坛中有朋友说这个问题,前两天刚好碰到,记录一下,方便其他朋友查阅。
        症状:
1、在ArcCatalog中,通过Local方式连接gis server没有问题,通过Internet方式连接(首先保证输入的字符串格式正确)提示:the request method (get.post,ect) was not allowed。。。。
2、ADF开发时(比如新建一个web mappling application模板),在MapResourceManager中,通过Local方式连接数据源没有问题,通过Internet连接时出错如下图:

        解决办法:很有可能是安装时未进行Web Application Post Install引起的,(重)做一遍Web Application Post Install即可。

ArcGIS Server网站发布后地图显示空白的原因之一

        一般来说,在地图网站发布后,如果地图区域显示为空白,但可以看到其他控件,可能是因为:1、引用的service运行不正常;2、通过local方式连接而没有添加arcgis identity;3、Web Server机器名中含有下划线“_”。但实际情况可能不止这些,碰到这个问题后只能耐心寻找原因来解决问题。
        今天刚好碰到了这个情况:用模板程序发布一个网站,mapresource manager中添加了一个经过cache的map service,本机浏览正常,但通过外网浏览的时候,界面显示正常,地图区域空白;如果引用一个没有经过cache的服务的话,外网和本机浏览都正常。网络是这样的,web server和gis server都在本机上,本机处于局域网中,通过路由的转发规则设置外网访问网络ip时自动转到本机ip上来。cache和非cache的服务区别就在于显示地图时,前者是直接获取服务器上的图片,而后者是gis server动态生成图片然后发送到客户端。那么可以看出是在获取缓存图片时出问题了,而本机可以访问到,外网却访问不到,那么估计可能和虚拟路径有关。在外网机器上查看http请求,发现如图情况:

        可以看出,在获取其他控件的图片时,使用了网络的对外ip,而获取cache图片时使用的确实本机名。毫无疑问是cache路径的虚拟目录设置不对。一般安装完ags后,设置cache,job,output所对应的虚拟路径时,习惯用hostname作为域名,这和iis设置相符,但如果要对外发布的话,要考虑到这个情况。更改了cache路径的虚拟目录后,外网浏览就程序就正常了。