WMS Layers Not Displaying in Runtime Without Name

1033
1
06-15-2017 03:04 PM
DarleneBanta1
New Contributor

How do I display the "root" layer in a WMS service using Runtime for .NET sdk?  This layer does not have a name property in the xml capabilities so I'm not sure how to specify it for the Layers property on the WmsLayer.  I can't seem to get any of the layers for this service to display.

I have tested with other services and they do seem to work when I specify the Layer's Name property, when every Layer in the WMS has a Name.

https://idpgis.ncep.noaa.gov/arcgis/services/NWS_Observations/NOHRSC_Snow_Analysis/MapServer/WmsServ...

This is an example xml:

<Layer>
<Title>
<![CDATA[ Layers ]]>
</Title>
<CRS>CRS:84</CRS>
<CRS>EPSG:4326</CRS>
<CRS>EPSG:0</CRS>
<EX_GeographicBoundingBox>
<westBoundLongitude>-130.516667</westBoundLongitude>
<eastBoundLongitude>-62.252731</eastBoundLongitude>
<southBoundLatitude>24.100000</southBoundLatitude>
<northBoundLatitude>58.240301</northBoundLatitude>
</EX_GeographicBoundingBox>
<BoundingBox CRS="CRS:84" minx="-130.516667" miny="24.100000" maxx="-62.252731" maxy="58.240301"/>
<BoundingBox CRS="EPSG:4326" minx="24.100000" miny="-130.516667" maxx="58.240301" maxy="-62.252731"/>
<BoundingBox CRS="EPSG:0" minx="-130.516667" miny="24.100000" maxx="-62.252731" maxy="58.240301"/>
<Layer queryable="1">
<Title>
<![CDATA[ Snow Water Equivalent ]]>
</Title>
<Abstract>
<![CDATA[ ]]>
</Abstract>
<CRS>CRS:84</CRS>
<CRS>EPSG:4326</CRS>
<CRS>EPSG:0</CRS>
<EX_GeographicBoundingBox>
<westBoundLongitude>-130.516666</westBoundLongitude>
<eastBoundLongitude>-62.252731</eastBoundLongitude>
<southBoundLatitude>24.100000</southBoundLatitude>
<northBoundLatitude>58.240301</northBoundLatitude>
</EX_GeographicBoundingBox>
<BoundingBox CRS="CRS:84" minx="-130.516666" miny="24.100000" maxx="-62.252731" maxy="58.240301"/>
<BoundingBox CRS="EPSG:4326" minx="24.100000" miny="-130.516666" maxx="58.240301" maxy="-62.252731"/>
<BoundingBox CRS="EPSG:0" minx="-130.516666" miny="24.100000" maxx="-62.252731" maxy="58.240301"/>
<Layer queryable="1">
<Name>1</Name>
<Title>
<![CDATA[ Inches ]]>
</Title>
<Abstract>
<![CDATA[ nws_nohrsc_snowWaterMos ]]>
</Abstract>
<CRS>CRS:84</CRS>
<CRS>EPSG:4326</CRS>
<CRS>EPSG:0</CRS>
<EX_GeographicBoundingBox>
0 Kudos
1 Reply
MatveiStefarov
Esri Contributor

Only named layers hold data in a WMS service. Unnamed layers are only used for logical grouping and metadata. The WMS specification provides more details (section 7.2.4):

Conceptually, each Layer is a distinct entity. However, as a means of classifying and organizing layers, and as a means of reducing the size of the service metadata, a single parent Layer may enclose any number of additional layers, which may be hierarchically nested as desired.

<...>

If, and only if, a layer has a <Name>, then it is a map layer that can be requested by using that Name in the LAYERS parameter of a GetMap request. A Layer that contains a <Name> element is referred to as a “named layer” in this International Standard. If the layer has a Title but no Name, then that layer is only a category title for all the layers nested within. A server that advertises a Layer containing a Name element shall be able to accept that Name as the value of LAYERS argument in a GetMap request and return the corresponding map. A client shall not attempt to request a layer that has a Title but no Name.

Runtime's WMSLayer takes a flattened list of named layers to display, ordered bottom-to-top. For this particular service, displaying the "root" layer just means creating a WMSLayer from names "1", "2", "3", "5", "6", and "7".

For a more general solution, you can examine WMSLayerInfo and gather all of its named sublayers recursively, like so:

/// <summary>
///   Gathers a flat list of named layers for a given WMSLayerInfo, recursively.
/// </summary>
/// <param name="startingNode">Parent node to begin the search at.</param>
/// <param name="collector">A list to be populated with named WmsLayerInfo objects.</param>
void GetNamedLayers(WmsLayerInfo startingNode, List<WmsLayerInfo> collector)
{
    if (!String.IsNullOrEmpty(startingNode.Name))
    {
        // Add this named layer to the list
        collector.Add(startingNode);
    }
    else
    {
        // For category layers: look for named children
        foreach (var sublayer in startingNode.LayerInfos)
        {
            GetNamedLayers(sublayer, collector);
        }
    }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Example usage:

// Load service metadata
var serviceUrl = new Uri("https://idpgis.ncep.noaa.gov/arcgis/services/NWS_Observations/NOHRSC_Snow_Analysis/MapServer/WmsServ...");
var service = new WmsService(serviceUrl);
await service.LoadAsync();

// Gather a list of all named WMSLayerInfos on this service
var list = new List<WmsLayerInfo>();
foreach (var layerInfo in service.ServiceInfo.LayerInfos)
{
    GetNamedLayers(layerInfo, list);
}

// Create a layer containing ALL named sublayers from this service, in order of declaration.
// Note: First layer in the list will be drawn first (at the bottom),
// and last layer will be drawn last (on top of everything else).
var layer = new WmsLayer(list);
await layer.LoadAsync();‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍