WMSMapServiceLayer.cs.org
上传用户:huazai0421
上传日期:2008-05-30
资源大小:405k
文件大小:16k
源码类别:
SilverLight
开发平台:
C#
- using System;
- using System.Diagnostics;
- using System.Net;
- using System.Text;
- using System.Windows;
- using System.Xml;
- using System.Xml.Linq;
- using ESRI.ArcGIS.Client;
- using ESRI.ArcGIS.Client.Geometry;
- using System.Globalization;
- using System.Collections.Generic;
- namespace ESRI.ArcGIS.Samples
- {
- /// <summary>
- /// A WMS service layer for the ArcGIS API for Microsoft Silverlight/WPF
- /// </summary>
- public class WMSMapServiceLayer : DynamicMapServiceLayer
- {
- string[] _layers;
- string[] _layersArray;
- string _proxyUrl;
- BoundingExtent _boundingExtent = new BoundingExtent();
- ESRI.ArcGIS.Client.Geometry.Envelope InitialExtent;
- // Coordinate system WKIDs in WMS 1.3 where X,Y (Long,Lat) switched to Y,X (Lat,Long)
- private int[,] LatLongCRSRanges = new int[,] { { 4001, 4999 },
- {2044, 2045}, {2081, 2083}, {2085, 2086}, {2093, 2093},
- {2096, 2098}, {2105, 2132}, {2169, 2170}, {2176, 2180},
- {2193, 2193}, {2200, 2200}, {2206, 2212}, {2319, 2319},
- {2320, 2462}, {2523, 2549}, {2551, 2735}, {2738, 2758},
- {2935, 2941}, {2953, 2953}, {3006, 3030}, {3034, 3035},
- {3058, 3059}, {3068, 3068}, {3114, 3118}, {3126, 3138},
- {3300, 3301}, {3328, 3335}, {3346, 3346}, {3350, 3352},
- {3366, 3366}, {3416, 3416}, {20004, 20032}, {20064, 20092},
- {21413, 21423}, {21473, 21483}, {21896, 21899}, {22171, 22177},
- {22181, 22187}, {22191, 22197}, {25884, 25884}, {27205, 27232},
- {27391, 27398}, {27492, 27492}, {28402, 28432}, {28462, 28492},
- {30161, 30179}, {30800, 30800}, {31251, 31259}, {31275, 31279},
- {31281, 31290}, {31466, 31700} };
- public WMSMapServiceLayer()
- : base()
- { }
- #region Public Properties
- /// <summary>
- /// Required. Gets or sets the URL to a WMS service endpoint.
- /// For example,
- /// http://sampleserver1.arcgisonline.com/ArcGIS/services/Specialty/ESRI_StatesCitiesRivers_USA/MapServer/WMSServer,
- /// http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi.
- /// </summary>
- /// <value>The URL.</value>
- public string Url
- {
- get;
- set;
- }
- /// <summary>
- /// Required. Gets or sets the unique layer ids in a WMS service.
- /// Each id is a string value. At least one layer id must be defined.
- /// </summary>
- /// <value>A string array of layer ids.</value>
- [System.ComponentModel.TypeConverter(typeof(StringToStringArrayConverter))]
- public string[] Layers
- {
- get { return _layersArray; }
- set
- {
- _layersArray = value;
- OnLayerChanged();
- }
- }
- /// <summary>
- /// Optional. Gets or sets the URL to a proxy service that brokers Web requests between the Silverlight
- /// client and a WMS service. Use a proxy service when the WMS service is not hosted on a site that provides
- /// a cross domain policy file (clientaccesspolicy.xml or crossdomain.xml). You can also use a proxy to
- /// convert png images to a bit-depth that supports transparency in Silverlight.
- /// </summary>
- /// <value>The proxy URL string.</value>
- public string ProxyUrl
- {
- get { return _proxyUrl; }
- set { _proxyUrl = value; }
- }
- /// <summary>
- /// Optional. Gets or sets the WMS version. If SkipGetCapabilities property is set to true, this value determines version requested.
- /// If SkipGetCapabilities is false, this value determines version to retrieve. If no value specified, default value returned from
- /// the site will be used.
- /// </summary>
- /// <value>The version string.</value>
- public string Version
- {
- get;
- set;
- }
- /// <summary>
- /// Optional. Gets or sets a value indicating whether to skip a request to get capabilities.
- /// Default value is false. Set SkipGetCapabilities if the site hosting the WMS service does not provide a
- /// cross domain policy file and you do not have a proxy page. In this case, you must set the WMS service version.
- /// If true, the initial and full extent of the WMS Silverlight layer will not be defined.
- /// </summary>
- public bool SkipGetCapabilities
- {
- get;
- set;
- }
- #endregion
- private bool initializing;
- /// <summary>
- /// Initializes this a WMS layer. Calls GetCapabilities if SkipGetCapabilities is false.
- /// </summary>
- public override void Initialize()
- {
- if (initializing || IsInitialized) return;
- initializing = true;
- if (SkipGetCapabilities)
- {
- base.Initialize();
- }
- else
- {
- string wmsUrl = string.Format("{0}{1}{2}",
- Url,
- "?service=WMS&request=GetCapabilities&version=",
- Version);
- WebClient client = new WebClient();
- client.DownloadStringCompleted += client_DownloadStringCompleted;
- client.DownloadStringAsync(PrefixProxy(wmsUrl));
- }
- }
- private Uri PrefixProxy(string url)
- {
- if (string.IsNullOrEmpty(ProxyUrl))
- return new Uri(url, UriKind.RelativeOrAbsolute);
- string proxyUrl = ProxyUrl;
- if (!proxyUrl.Contains("?"))
- {
- if (!proxyUrl.EndsWith("?"))
- proxyUrl = ProxyUrl + "?";
- }
- else
- {
- if (!proxyUrl.EndsWith("&"))
- proxyUrl = ProxyUrl + "&";
- }
- if (ProxyUrl.StartsWith("~") || ProxyUrl.StartsWith("../")) //relative to xap root
- {
- string uri = Application.Current.Host.Source.AbsoluteUri;
- int count = proxyUrl.Split(new string[] { "../" }, StringSplitOptions.None).Length;
- for (int i = 0; i < count; i++)
- {
- uri = uri.Substring(0, uri.LastIndexOf("/"));
- }
- if (!uri.EndsWith("/"))
- uri += "/";
- proxyUrl = uri + proxyUrl.Replace("~", "").Replace("../", "");
- }
- else if (ProxyUrl.StartsWith("/")) //relative to domain root
- {
- proxyUrl = ProxyUrl.Replace("/", string.Format("{0}://{1}:{2}",
- Application.Current.Host.Source.Scheme,
- Application.Current.Host.Source.Host,
- Application.Current.Host.Source.Port));
- }
- UriBuilder b = new UriBuilder(proxyUrl);
- b.Query = url;
- return b.Uri;
- }
- private List<string> LayerList;
- class LayerInfo
- {
- public string Name { get; set; }
- public string Title { get; set; }
- public string Abstract { get; set; }
- public Envelope Extent { get; set; }
- public IList<LayerInfo> ChildLayers { get; set; }
- }
- internal void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
- {
- if (!CheckForError(e))
- {
- // Will be set when capabilities processed
- InitialExtent = new ESRI.ArcGIS.Client.Geometry.Envelope();
- // Process capabilities file
- XDocument xDoc = XDocument.Parse(e.Result);
- LayerList = new List<string>();
- processNode(xDoc);
- // Define full extent when all included layers are processed
- FullExtent = new Envelope(_boundingExtent.XMin, _boundingExtent.XMax,
- _boundingExtent.YMin, _boundingExtent.YMax);
- }
- // Call initialize regardless of error
- base.Initialize();
- }
- #region Process Capabilities
- bool initExtent = false;
- bool addToFullExtent = false;
- private void processNode(XNode node)
- {
- switch (node.NodeType)
- {
- case XmlNodeType.Document:
- XDocument document = (XDocument)node;
- foreach (XNode n in document.Nodes())
- {
- processNode(n);
- }
- break;
- case XmlNodeType.Element:
- XElement element = (XElement)node;
- Debug.WriteLine("StartElement: {0}", element.Name);
- if (element.Name.LocalName == "Layer")
- {
- LayerInfo layer = ParseLayerNode(element);
- }
- // 1.1.1 layer name
- if (element.Name.LocalName == "Name" && element.Value == _layersArray[0])
- {
- initExtent = true;
- addToFullExtent = true;
- }
- else if (element.Name.LocalName == "Name")
- for (int i = 0; i < _layersArray.Length; i++)
- {
- if (element.Value == _layersArray[i])
- addToFullExtent = true;
- }
- // 1.3
- if (element.Name.LocalName == "EX_GeographicBoundingBox")
- initExtent = true;
- if (initExtent && element.Parent.Name.LocalName == "EX_GeographicBoundingBox")
- {
- switch (element.Name.LocalName)
- {
- case "westBoundLongitude":
- InitialExtent.XMin = Double.Parse(element.Value);
- break;
- case "eastBoundLongitude":
- InitialExtent.XMax = Double.Parse(element.Value);
- break;
- case "southBoundLatitude":
- InitialExtent.YMin = Double.Parse(element.Value);
- break;
- case "northBoundLatitude":
- InitialExtent.YMax = Double.Parse(element.Value);
- break;
- }
- }
- if (element.HasAttributes)
- {
- foreach (XAttribute attribute in element.Attributes())
- {
- if ((element.Name.LocalName == "WMT_MS_Capabilities" ||
- element.Name.LocalName == "WMS_Capabilities") &&
- attribute.Name.LocalName == "version")
- {
- Version = attribute.Value;
- }
- //--- 1.1.1
- if (initExtent && element.Name.LocalName == "BoundingBox")
- {
- switch (attribute.Name.LocalName)
- {
- case "minx":
- InitialExtent.XMin = Double.Parse(attribute.Value);
- break;
- case "miny":
- InitialExtent.YMin = Double.Parse(attribute.Value);
- break;
- case "maxx":
- InitialExtent.XMax = Double.Parse(attribute.Value);
- break;
- case "maxy":
- InitialExtent.YMax = Double.Parse(attribute.Value);
- break;
- }
- }
- if (addToFullExtent && element.Name.LocalName == "BoundingBox")
- {
- switch (attribute.Name.LocalName)
- {
- case "minx":
- _boundingExtent.XMin = Double.Parse(attribute.Value);
- break;
- case "miny":
- _boundingExtent.YMin = Double.Parse(attribute.Value);
- break;
- case "maxx":
- _boundingExtent.XMax = Double.Parse(attribute.Value);
- break;
- case "maxy":
- _boundingExtent.YMax = Double.Parse(attribute.Value);
- break;
- }
- }
- Debug.WriteLine("Attribute: {0} = {1}", attribute.Name, attribute.Value);
- }
- // Define initial extent (first layer) and full extent (all layers)
- if (initExtent && element.Name.ToString().Contains("BoundingBox"))
- initExtent = false;
- if (addToFullExtent && element.Name.ToString().Contains("BoundingBox"))
- addToFullExtent = false;
- if (!element.IsEmpty)
- {
- foreach (XNode n in element.Nodes())
- {
- processNode(n);
- }
- }
- Debug.WriteLine("EndElement: {0}", element.Name);
- break;
- }
- break;
- default:
- break;
- }
- }
- private LayerInfo ParseLayerNode(XElement element)
- {
- LayerInfo info = new LayerInfo();
- foreach (XNode node in element.Nodes())
- {
- if (node.NodeType == XmlNodeType.Element)
- {
- XElement e = (XElement)node;
- if (e.Name.LocalName == "Name")
- info.Name = e.Value;
- else if (e.Name.LocalName == "Title")
- info.Title = e.Value;
- else if (e.Name.LocalName == "Abstract")
- info.Abstract = e.Value;
- else if (e.Name.LocalName == "Layer")
- {
- if (info.ChildLayers == null)
- info.ChildLayers = new List<LayerInfo>();
- info.ChildLayers.Add(ParseLayerNode(e));
- }
- }
- }
- return info;
- }
- #endregion
- private bool CheckForError(DownloadStringCompletedEventArgs e)
- {
- if (e.Cancelled)
- {
- InitializationFailure = new Exception("Request Cancelled");
- return true;
- }
- if (e.Error != null)
- {
- Exception ex = e.Error;
- if (ex is System.Security.SecurityException)
- {
- ex = new System.Security.SecurityException(
- @"A security exception occured while trying to connect to the WMS service.
- Make sure you have a cross domain policy file available at the root for your server that allows for requests from this application.
- If not, use a proxy page (handler) to broker communication.",
- ex);
- }
- InitializationFailure = ex;
- return true;
- }
- return false;
- }
- /// <summary>
- /// Gets the URL. Override from DynamicMapServiceLayer
- /// </summary>
- /// <param name="extent">The extent.</param>
- /// <param name="width">The width.</param>
- /// <param name="height">The height.</param>
- /// <param name="onComplete">OnUrlComplete delegate.</param>
- /// <remarks>
- /// The Map has a private method loadLayerInView which calls Layer.Draw.
- /// The DynamicMapServiceLayer abstract class overrides the Draw method and calls
- /// DynamicMapServiceLayer.GetUrl which must be implemented in a subclass.
- /// The last parameter is the OnUrlComplete delegate, which is used to pass the appropriate values
- /// (url, width, height, envelope) to the private DynamicMapServiceLayer.getUrlComplete method.
- /// </remarks>
- public override void GetUrl(ESRI.ArcGIS.Client.Geometry.Envelope extent, int width, int height,
- DynamicMapServiceLayer.OnUrlComplete onComplete)
- {
- int extentWKID = extent.SpatialReference.WKID;
- StringBuilder mapURL = new StringBuilder(Url);
- mapURL.Append("?SERVICE=WMS");
- mapURL.Append("&REQUEST=GetMap");
- mapURL.AppendFormat("&WIDTH={0}", width);
- mapURL.AppendFormat("&HEIGHT={0}", height);
- mapURL.AppendFormat("&FORMAT={0}", "image/png");
- mapURL.AppendFormat("&LAYERS={0}", String.Join(",", Layers));
- mapURL.Append("&STYLE=");
- mapURL.AppendFormat("&BGCOLOR={0}", "0xFFFFFF");
- mapURL.AppendFormat("&TRANSPARENT={0}", "true");
- mapURL.AppendFormat("&VERSION={0}", Version);
- switch (Version)
- {
- case ("1.1.1"):
- mapURL.AppendFormat("&SRS=EPSG:{0}", extentWKID);
- mapURL.AppendFormat("&bbox={0},{1},{2},{3}", extent.XMin, extent.YMin, extent.XMax, extent.YMax);
- break;
- case ("1.3"):
- case ("1.3.0"):
- mapURL.AppendFormat("&CRS=EPSG:{0}", extentWKID);
- bool useLatLong = false;
- int length = LatLongCRSRanges.Length / 2;
- for (int count = 0; count < length; count++)
- {
- if (extentWKID >= LatLongCRSRanges[count, 0] && extentWKID <= LatLongCRSRanges[count, 1])
- {
- useLatLong = true;
- break;
- }
- }
- if (useLatLong)
- mapURL.AppendFormat(CultureInfo.InvariantCulture,
- "&BBOX={0},{1},{2},{3}", extent.YMin, extent.XMin, extent.YMax, extent.XMax);
- else
- mapURL.AppendFormat(CultureInfo.InvariantCulture,
- "&BBOX={0},{1},{2},{3}", extent.XMin, extent.YMin, extent.XMax, extent.YMax);
- break;
- }
- onComplete(PrefixProxy(mapURL.ToString()).AbsoluteUri, width, height, new ESRI.ArcGIS.Client.Geometry.Envelope()
- {
- XMin = extent.XMin,
- YMin = extent.YMin,
- XMax = extent.XMax,
- YMax = extent.YMax
- });
- }
- internal class BoundingExtent
- {
- double _xmin = double.MaxValue;
- double _ymin = double.MaxValue;
- double _xmax = double.MinValue;
- double _ymax = double.MinValue;
- public double XMin
- {
- get { return _xmin; }
- set { if (value < _xmin) _xmin = value; }
- }
- public double YMin
- {
- get { return _ymin; }
- set { if (value < _ymin) _ymin = value; }
- }
- public double XMax
- {
- get { return _xmax; }
- set { if (value > _xmax) _xmax = value; }
- }
- public double YMax
- {
- get { return _ymax; }
- set { if (value > _ymax) _ymax = value; }
- }
- }
- /// <summary>
- /// String To String Array Converter
- /// </summary>
- public sealed class StringToStringArrayConverter : System.ComponentModel.TypeConverter
- {
- public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType)
- {
- return (sourceType == typeof(string));
- }
- public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
- {
- if (value == null)
- return null;
- if (value is string)
- {
- string[] values = (value as string).Replace(" ", "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
- if (values.Length == 0)
- return null;
- return values;
- }
- throw new NotSupportedException("Cannot convert to string array");
- }
- }
- }
- }