我正在尝试使用c#mapscript处理GetFeaturInfo WMS请求。在使用mapscript之前,我们的软件将WMS请求传递给IIS上托管的CGI映射服务器。这处理了与每个查询图层关联的html模板,并在模板中替换了许多令牌以获取数据。
我们不能使用mapserver cgi实现,所以我试图通过C#mapscript机制使用mapscript重新实现这个机制。
我到目前为止的代码摘要在这里。这个问题是对processQueryTemplate的调用导致抛出AccessViolation异常。
public string GetFeatureInfoFromWMS(NameValueCollection WMSqueryString)
{
//Set the projection library environment variable used by mapscript.dll
Environment.SetEnvironmentVariable("PROJ_LIB", ProjectionLibraryPath);
string output = string.Empty;
try
{
using (mapObj map = new mapObj(MapFile))
{
//Add aditional layer specific params - ie location of plugins etc
ProcessLayers(map, WMSqueryString);
map.web.metadata.set("wms_onlineresource", WMSOnlineResourceURL);
string xVal = WMSqueryString["X"];
string yVal = WMSqueryString["Y"];
if (xVal == null || yVal == null)
{
throw new ArgumentNullException("The X or Y point value has not been suppplied in the GetFeatureInfo request");
}
double pointX = 0.0;
double pointY = 0.0;
try
{
pointX = Convert.ToDouble(xVal);
pointY = Convert.ToDouble(yVal);
}
catch (Exception e)
{
throw new ArgumentException("The X or Y point value supplied in the GetFeatureInfo request is not a valid decimal",e);
}
string layersQS = WMSqueryString["QUERY_LAYERS"];
if (layersQS == null)
{
throw new ArgumentNullException("The QUERY_LAYERS parameter of the WMS GetFeatureInfo request is not specified correctly");
}
//Load the parameters from the wms request into the map
using (OWSRequest request = new OWSRequest())
{
for (int i = 0; i < WMSqueryString.Count; i++)
{
request.setParameter(WMSqueryString.GetKey(i), WMSqueryString.Get(i));
}
string wmsVersion = WMSqueryString["VERSION"];
if (wmsVersion == null || wmsVersion == string.Empty) wmsVersion = DEFAULT_WMS_VERSION;
map.loadOWSParameters(request, wmsVersion);
}
//Reproject X & Y pixel co-ordinates in map co-ordintes.
double minX = map.extent.minx;
double maxX = map.extent.maxx;
double geoX = minX + ((pointX / (double)map.width) * (maxX - minX));
double minY = map.extent.miny;
double maxY = map.extent.maxy;
double geoY = maxY - ((pointY / (double)map.height) * (maxY - minY));
string[] queryLayers = layersQS.Split(',');
using (pointObj point = new pointObj(geoX, geoY, 0, 0))
{
foreach (string layerName in queryLayers)
{
using (layerObj layer = map.getLayerByName(layerName))
{
int queryResult = layer.queryByPoint(map, point, (int)MS_QUERY_MODE.MS_QUERY_SINGLE, -1);
}
}
}
map.prepareQuery();
string[] names = { "Token1" };
string[] values = { "Value1" };
//BANG!!!!!!
output = map.processQueryTemplate(names, values, 10);
}
return output;
}
catch (Exception ex)
{
throw;
}
}
关联的地图文件如下:
MAP
#
# Start of map file
#
NAME esdm
STATUS ON
TEMPLATEPATTERN "."
SIZE 400 600
UNITS meters
EXTENT 0 0 800000 1200000
IMAGECOLOR 255 255 255
FONTSET fonts.txt
#DEBUG ON
IMAGETYPE PNG
PROJECTION
"init=epsg:27700"
END
OUTPUTFORMAT
NAME "png"
DRIVER "GD/PNG"
IMAGEMODE RGBA
MIMETYPE image/png
EXTENSION png
TRANSPARENT ON
END
# OUTPUTFORMAT
# NAME "imagemap"
# MIMETYPE text/html; driver=imagemap
# DRIVER "imagemap"
# END
#
# Start of web interface definition (including WMS enabling metadata)
#
WEB
METADATA
"wms_title" "SQL mapping data"
"wms_srs" "EPSG:27700 EPSG:4326 EPSG:54004 EPSG:54005 EPSG:900913"
"wms_feature_info_mime_type" "text/plain"
"wms_include_items" "all"
END
END
INCLUDE "mapSymbols.inc"
# BARSActions Point Layer
#-----------------------------------------------------------------------------------------
LAYER
NAME "Actions"
MAXSCALEDENOM 100000000
MINSCALEDENOM 0
METADATA
"wms_title" "BARSActions"
"wfs_title" "BARSActions"
"wms_srs" "EPSG:27700"
END
CONNECTIONTYPE PLUGIN
PLUGIN "SQLPlugin"
DATA "geom from MapLoadTest USING UNIQUE ActionId USING SRID=27700"
FILTER "(OrgUnitId = 1 AND %ActionStatusID% AND %ActionTypeID% AND %AreaIDST(geom)%)"
TYPE POINT
STATUS ON
TOLERANCE 50
TEMPLATE "barsTemplate.htm"
CLASS
COLOR 0 0 255
OUTLINECOLOR 0 0 0
SYMBOL 'star'
SIZE 15
#MAXSIZE 6
#MINSIZE 3
END # end of class object
PROJECTION
"init=epsg:27700"
END
DUMP True
END # end of layer object
# BARSActions Polygon Layer
#-----------------------------------------------------------------------------------------
LAYER
NAME "ActionsPolygons"
MAXSCALEDENOM 100000000
MINSCALEDENOM 0
METADATA
"wms_title" "BARSActionsPolygons"
"wfs_title" "BARSActionsPolygons"
"wms_srs" "EPSG:27700"
END
CONNECTIONTYPE PLUGIN
PLUGIN "SQLPlugin"
DATA "geom from MapLoadTest USING UNIQUE ActionId USING SRID=27700"
FILTER "(OrgUnitId = 2 AND ActionID = 200 AND %ActionStatusID% AND %ActionTypeID% AND %AreaIDST(geom)%)"
TYPE POLYGON
STATUS ON
TOLERANCE 50
TEMPLATE "barsTemplate.htm"
CLASS
COLOR 0 0 255
OUTLINECOLOR 0 0 0
END # end of class object
PROJECTION
"init=epsg:27700"
END
DUMP True
END # end of layer object
END # Map File
映射文件中的各个项目都是标记化的(即sql插件位置和应用于数据的过滤器)这是通过在前一个方法中调用ProcessLayers来处理的。绘制地图时,此机制似乎不会导致任何问题。对queryByPoint的调用有效。它返回成功,针对sql db运行的查询返回预期数据。
我不确定从这里开始的地方以及从模板生成输出还需要做些什么。我期待调用processQueryTemplate来返回填充的模板。我也不太清楚prepareQuery应该做什么。
干杯
答案 0 :(得分:1)
从未想过如何让模板发挥作用。但是我设法获取查询返回的形状的数据库ID。然后我使用这些来在其他地方准备HTML结果。
请注意,我正在使用map.querybypoint来处理存在图层组的情况(在这种情况下,图层组名称将作为wms请求中的图层名称出现。
/// <summary>
/// Handles a GetFeature info request and returns matching ActionID's.
/// </summary>
/// <param name="WMSqueryString">The WM squery string.</param>
/// <returns>A list of matching action ID's.</returns>
/// <exception cref="ArgumentNullException">Thrown if the X or Y point values are not supplied in the WMS GetFeatureInfo request</exception>
/// <exception cref="ArgumentException">Thrown in the X or Y point values supplied in the WMS GetFeatureInfo request cannot be converted to valid doubles</exception>
public List<int> GetFeatureInfoActionID(NameValueCollection WMSqueryString)
{
//Set the projection library environment variable used by mapscript.dll
Environment.SetEnvironmentVariable("PROJ_LIB", ProjectionLibraryPath);
try
{
List<int> resultsList = new List<int>();
using (mapObj map = new mapObj(MapFile))
{
ProcessLayers(map, WMSqueryString);
map.web.metadata.set("wms_onlineresource", WMSOnlineResourceURL);
//Load the parameters from the wms request into the map
using (OWSRequest request = new OWSRequest())
{
for (int i = 0; i < WMSqueryString.Count; i++)
{
request.setParameter(WMSqueryString.GetKey(i), WMSqueryString.Get(i));
}
string wmsVersion = WMSqueryString["VERSION"];
if (wmsVersion == null || wmsVersion == string.Empty) wmsVersion = DEFAULT_WMS_VERSION;
map.loadOWSParameters(request, wmsVersion);
}
string xVal = WMSqueryString["X"];
string yVal = WMSqueryString["Y"];
if (xVal == null || yVal == null)
{
throw new ArgumentNullException("The X or Y point value has not been suppplied in the GetFeatureInfo request");
}
double pointX = 0.0;
double pointY = 0.0;
try
{
pointX = Convert.ToDouble(xVal);
pointY = Convert.ToDouble(yVal);
}
catch (Exception e)
{
throw new ArgumentException("The X or Y point value supplied in the GetFeatureInfo request is not a valid decimal",e);
}
//Reproject X & Y pixel co-ordinates in map co-ordintes.
double minX = map.extent.minx;
double maxX = map.extent.maxx;
double geoX = minX + ((pointX / (double)map.width) * (maxX - minX));
double minY = map.extent.miny;
double maxY = map.extent.maxy;
double geoY = maxY - ((pointY / (double)map.height) * (maxY - minY));
MS_RETURN_VALUE queryResult;
using (pointObj point = new pointObj(geoX, geoY, 0, 0))
{
queryResult = (MS_RETURN_VALUE)map.queryByPoint(point, (int)MS_QUERY_MODE.MS_QUERY_MULTIPLE, -1);
}
if (queryResult != MS_RETURN_VALUE.MS_SUCCESS)
{
return null;
}
map.prepareQuery();
for (int layerIndex = 0; layerIndex < map.numlayers; layerIndex++)
{
using (layerObj layer = map.getLayer(layerIndex))
{
int resultCount = layer.getNumResults();
if (resultCount > 0)
{
layer.open();
for (int resultIndex = 0; resultIndex < resultCount; resultIndex++)
{
using (resultCacheMemberObj resultCache = layer.getResult(resultIndex))
{
int actionID = resultCache.shapeindex;
if (actionID != 0 && resultsList.Contains(actionID) == false)
{
resultsList.Add(actionID);
}
}
}
layer.close();
}
}
}
}
return resultsList;
}
catch (Exception ex)
{
throw;
}
}